精华内容
下载资源
问答
  • NULL 博文链接:https://zmx.iteye.com/blog/688299
  • Spring框架核心之一便是依赖注入依赖注入主要实现是通过java反射,他是如何工作以及要得到的目的是什么,可以通过以下代码实战可以了解到。 如果你像了解依赖注入的详细概念可以参考以下博客...

    依赖注入DI

    依赖注入简单来讲就就是对象在被创建的时候,所有依赖关系由一个调控系统管理和传递给他。也可以说,依赖被注入到对象中。Spring框架核心之一便是依赖注入,依赖注入主要实现是通过java反射,他是如何工作以及要得到的目的是什么,可以通过以下代码实战可以了解到。

    如果你像了解依赖注入的详细概念可以参考以下博客https://blog.csdn.net/sinat_21843047/article/details/80297951

    注解定义

    注解:Component,该注解用来描述需要容器管理的bean

    package ioc;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    // 确认bean的注解
    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Component {
        String value();
    }
    

    注解:Quatifier,该注解用来描述依赖关系

    package ioc;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    // 确认需要依赖注入的bean
    @Target({ ElementType.FIELD })
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Quatifier {
        String value();
    }
    

    依赖实例

    通过定义的注解描述,我们定义了person和hobby两个bean,并且person需要依赖hobby才能正常使用

    package ioc;
    @Component("person")
    public class Person {
        
        @Quatifier("hobby")
        private Hobby hobby;
        public void say() {
            hobby.like();
        }
    }
    
    package ioc;
    @Component("hobby")
    public class Hobby {
        public void like() {
            System.out.println("I love programming");
        }
    }
    

    依赖注入调控系统实现核心

    package ioc;
    import java.io.File;
    import java.lang.reflect.Field;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    public class Context {
        // 保存项目中所有类的全类名
        private static List<String> packageNames = new ArrayList<String>();
        // 所有类的实例,key是注解的值,value为类的实例
        private static Map<String, Object> instanceMap = new HashMap<String, Object>();
        // 构造时初始化bean
        public Context() {
            scanPackage("");
            filterAndInstance();
            ioc();
        }
        /**
         * 扫描项目中所有class文件,将全类名放入packageNames容器管理
         *
         * @param sPackage 包名
         */
        private void scanPackage(String sPackage) {
            if (!"".equals(sPackage)) sPackage += "/";
            String pathFile = this.getClass().getClassLoader().getResource(sPackage).getFile();  // 获取项目根目录
            File file = new File(pathFile);
            String fileList[] = file.list();
            if (fileList == null) return;
            for (String path : fileList) {
                File eachFile = new File(pathFile + path);
                if (eachFile.isDirectory()) {
                    scanPackage(sPackage + eachFile.getName());
                } else {
                    if (eachFile.getName().lastIndexOf(".class") > 0) {    // 记录类的绝对路径
                        packageNames.add(sPackage.replaceAll("/", ".")
                                + eachFile.getName().replaceAll("\\.class", ""));
                    }
                }
            }
        }
        /**
         * 实例化组建,并放入instanceMap容器中管理
         * 只管理Component注解下的bean
         */
        private void filterAndInstance() {
            if (packageNames.isEmpty())
                return;
            for (String className : packageNames) {
                try {
                    Class<?> cName = Class.forName(className);
                    if (cName.isAnnotationPresent(Component.class)) {
                        Object instance = cName.newInstance();
                        Component component = cName.getAnnotation(Component.class);
                        String key = component.value();
                        instanceMap.put(key, instance);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        /**
         * 依赖注入,根据Quatifier注解,注入相关的bean
         */
        private void ioc() {
            if (instanceMap.isEmpty())
                return;
            for (Map.Entry<String, Object> entry : instanceMap.entrySet()) {
                // 拿到类的的所有属性
                Field fields[] = entry.getValue().getClass().getDeclaredFields();
                for (Field field : fields) {
                    field.setAccessible(true);// 可访问私有属性
                    if (field.isAnnotationPresent(Quatifier.class)) {
                        Quatifier quatifier = field.getAnnotation(Quatifier.class);
                        String value = quatifier.value();
                        try {
                            field.set(entry.getValue(), instanceMap.get(value));
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        // 根据Component注解的值获取bean
        private Object getBean(String beanName) {
            return instanceMap.get(beanName);
        }
        // 测试
        public static void main(String[] args) {
            Context ctx = new Context();
            Person person = (Person) ctx.getBean("person");
            person.say();
        }
    }
    /*output
    * I love programming
    * */
    

    从main方法测试输出I love programming测试ok,这个简单的依赖注入实现就完成了



    、﹗∕
    — 〇 -
    ╱︱ ヽ
    但行好事、莫问前程!
    >.freerme[https://blog.csdn.net/freerme]
    _________________ *_*______
    ____ ____ ____
    展开全文
  • 在.net core中使用依赖注入是很常见的,最常见的我们会使用以下三种 services.AddScoped<TestIBLL, TestBLL>(); services.AddSingleton<TestIBLL, TestBLL>(); services.AddTransient<TestIBLL, ...

    在.net core中使用依赖注入是很常见的,最常见的我们会使用以下三种

    services.AddScoped<TestIBLL, TestBLL>();
    services.AddSingleton<TestIBLL, TestBLL>();
    services.AddTransient<TestIBLL, TestBLL>();

    当我们的业务层内容不多的时候这样写没有什么问题,但是加入有100个BLL呢,那样一个一

    个加会很麻烦,每加一个就要多写一次,而且容易忘记漏掉。

    那么我们的需求是让希望能够实现批量注入,并且可以按照不同的生命周期去实现自动注入,以避免每加一个业务类,就要写一次services.AddScoped<>();

    我将通过反射+特性来实现它。

     1.首先新建一个类ServiceAttribute,该类要继承Attribute,定义一个属性LifeTime,用它来接收注入时需要的生命周期,默认等于ServiceLifetime.Scoped,使用ServiceLifetime.Scoped需要导入using Microsoft.Extensions.DependencyInjection命名空间。

    /// <summary>
        /// 属性形式定义生命周期
        /// 默认Scoped
        /// </summary>
        [AttributeUsage(AttributeTargets.Class)]
        public class ServiceAttribute:Attribute
        {
            public ServiceLifetime LifeTime { get; set; }
            public ServiceAttribute(ServiceLifetime serviceLifetime= ServiceLifetime.Scoped)
            {
                LifeTime = serviceLifetime;
            }
        }

    2.在自己需要注入的业务类中加上ServiceAttribute特性,并给上生命周期,也可以不给,就默认是Scoped

      [Service(ServiceLifetime.Scoped)]
        public class TestBLL:TestIBLL
        {
        }
        public interface TestIBLL
        {
    
        }

    3.核心部分,新建一个IServiceCollection的扩展方法类,取名叫ServiceCollectionExpand,定义扩展方法AddBusiness

    1.获取当前程序域中的所有程序集,然后获取每个程序集中的所有type,得到其中包含有我们写的ServiceAttribute特性的类。

    2.遍历types,得到每一个type所继承的接口数组和它注入的生命周期的值,然后根据生命周期实现注入, service.AddSingleton(,)和service.AddSingleton<>()不同的是传入的参数不同,前者的两个值都是type类型,后者是两个泛型

    /// <summary>
        /// IServiceCollection扩展类
        /// </summary>
        public static class ServiceCollectionExpand
        {
            /// <summary>
            /// 按特性中的生命周期注入业务组件
            /// </summary>
            /// <param name="service"></param>
            public static void AddBusiness(this IServiceCollection service)
            {
                //获取有ServiceAttribute特性的所有类
                List<Type> types = AppDomain.CurrentDomain
                    .GetAssemblies()
                    .SelectMany(x => x.GetTypes())
                    .Where(t => t.IsClass && !t.IsAbstract 
                            && t.GetCustomAttributes(typeof(ServiceAttribute), false).Length > 0
                            )
                    .ToList();
    
                types.ForEach(impl=> 
                {
                    //获取该类所继承的所有接口
                    Type[] interfaces = impl.GetInterfaces();
                    //获取该类注入的生命周期
                    var lifetime = impl.GetCustomAttribute<ServiceAttribute>().LifeTime;
    
                    interfaces.ToList().ForEach(i => 
                    {
                        switch (lifetime)
                        {
                            case ServiceLifetime.Singleton:
                                service.AddSingleton(i,impl);
                                break;
                            case ServiceLifetime.Scoped:
                                service.AddScoped(i, impl);
                                break;
                            case ServiceLifetime.Transient:
                                service.AddTransient(i, impl);
                                break;
                        }
                    });
                });
    
            }
    
        }

    4.然后在startup类中的configureservices方法中调用扩展方法即可实现自动注入了

    public void ConfigureServices(IServiceCollection services)
            {
                services.AddControllers();
    
    
                #region 注册业务组件
                services.AddBusiness();
                #endregion
    
    
    
            }

    使用的话,在控制器中和以前一样使用即可。有反射的基础知识再看的话会比较容易明白。

    也有很多第三方组件可以实现批量依赖注入,比如autofac,Unity等。

    展开全文
  • 谈谈C#中的基于反射机制的依赖注入

    千次阅读 2020-03-19 15:07:31
    这相当于进一步的解耦,因为有 new 操作符后面总得跟类型,一跟类型就有了紧耦合的依赖。依靠反射创建类型不再需要 new 操作符也无需静态类型,这样使得很多时候耦合可以松到忽略不计。 反射不是 C# 语言的功能,...

     

    反射 Reflection

    反射:你给我一个对象,我能在不用 new 操作符也不知道该对象的静态类型的情况下,我能给你创建出一个同类型的对象,还能访问该对象的各个成员。

    这相当于进一步的解耦,因为有 new 操作符后面总得跟类型,一跟类型就有了紧耦合的依赖。依靠反射创建类型不再需要 new 操作符也无需静态类型,这样使得很多时候耦合可以松到忽略不计。

    反射不是 C# 语言的功能,而是 .NET 框架的功能,所以 .NET 框架支持的语言都能使用反射功能。

    C# 和 Java 这种托管类型的语言和 C、C++ 这些原生类型的语言区别之一就是反射

    单元测试、依赖注入、泛型编程都是基于反射机制

    本来反射应该是个很复杂的东西,但因为 .NET 和 C# 设计得精妙,导致时常我们是在使用反射却感觉不到它的存在,也使得反射用起来并不复杂。

    当程序处于动态期(dynamic)用户已经用上了,不再是开发时的静态期(static)。动态期用户和程序间的操作是难以预测的,如果你要在开始时将所有情况都预料到,那程序的复杂度难免太高,指不定就是成百上千的 if else,即使你真的这样做了,写出来的程序也非常难维护,可读性很低。很多时候更有可能是我们在编写程序时无法详尽枚举出用户可能进行的操作,这时我们的程序就需要一种以不变应万变的能力

    注:

    1. .NET Framework 和 .NET Core 都有反射机制,但它们的类库不太一样,使用反射时用到的一些 API 也略有差别,示例是基于 .NET Core 的

    2. 反射毕竟是动态地去内存中获取对象的描述、对象类型的描述,再用这些描述去创建新的对象,整个过程会影响程序性能,所以不要盲目过多地使用反射

    依赖注入

    例一:反射的原理以及和反射密切相关的一个重要技能 —— 依赖注入

    例一沿用的是我上一篇文章https://blog.csdn.net/weixin_41372626/article/details/104956082 中 Tank 的例子

    static void Main(string[] args)
    {
        // ITank、HeavyTank 这些都算静态类型
        ITank tank = new HeavyTank();
    
        // ======华丽的分割线======
        // 分割线以下不再使用静态类型
        var t = tank.GetType();
        object o = Activator.CreateInstance(t);
        MethodInfo fireMi = t.GetMethod("Fire");
        MethodInfo runMi = t.GetMethod("Run");
        fireMi.Invoke(o, null);
        runMi.Invoke(o, null);
    }
    ...

    CreateInstance 创建出来的对象是 object 的,我们并不知道它的静态类型是什么。

    public static object CreateInstance(Type type);

    我们平时大多数是用封装好了的反射方法,上面这种用法很少见。

    封装好了的反射最重要的一个功能就是依赖注入 DI Dependency Injection。前面学的那个依赖反转的全称是 DIP 别和 DI 搞混,但换句话说没有依赖反转也就没有依赖注入。

    依赖反转是一个概念,依赖注入是在该概念之上结合接口和反射机制所形成的一个应用。

    依赖注入框架

    依赖注入需要借助依赖注入框架,.NET Core 的依赖注入框架就是:Microsoft.Extensions.DependencyInjection

    依赖注入最重要的元素就是 Container(容器),我们把各种各样的类型和它们对应的接口都放在(注册)容器里面。回头我们创建实例时就找容器要。

    容器又叫做 Service Provider

    在注册类型时我们可以设置容器创建对象的规则:每次给我们一个新对象或是使用单例模式,每次要的时候容器都给我们同一个实例。

    具体怎么使用容器此处按下表,主要还是看依赖注入怎么用。

    static void Main(string[] args)
    {
        // ServiceCollection 就是容器
        var sc = new ServiceCollection();
        // 添加 ITank,并设置其对应的实现类是 HeavyTank
        sc.AddScoped(typeof(ITank), typeof(HeavyTank));
        var sp = sc.BuildServiceProvider();
        // ===========分割线===========
        // 分割线上面是整个程序的一次性注册,下面是具体使用
        ITank tank = sp.GetService<ITank>();
        tank.Fire();
        tank.Run();
    }

    通过上面这种方法,一旦以后我的 ITank 需要改为 MediumTank, 只需要改一句话即可。

    static void Main(string[] args)
    {
        // ServiceCollection 就是容器
        var sc = new ServiceCollection();
        sc.AddScoped(typeof(ITank), typeof(MediumTank));
        sc.AddScoped(typeof(IVehicle), typeof(Car));
        sc.AddScoped<Driver>();
        var sp = sc.BuildServiceProvider();
        // ===========分割线===========
        var driver = sp.GetService<Driver>();
        driver.Drive();
    }

    Driver 创建时本来需要一个 IVehicle 对象,sp 会去容器里面找,又由于我们注册了 IVehicle 的实现类是 Car,所以会自动创建一个 Car 实例传入 Driver 的构造器

     

     

    展开全文
  • ioc的依赖注入主要是靠反射实现,本文不讲解ioc。实现如下 创建Service ackage com.company.Spring; /** * @program: demo * @description: service层 * @author: wl * @create: 2020-06-27 15:15 **/ public ...

    手动实现IOC依赖注入

    ioc的依赖注入主要是靠反射实现,本文不讲解ioc。实现如下

    创建Service

    ackage com.company.Spring;
    
    /**
     * @program: demo
     * @description: service层
     * @author: wl
     * @create: 2020-06-27 15:15
     **/
    public class Service {
    }
    
    

    创建Controller

    package com.company.Spring;
    
    /**
     * @program: demo
     * @description: controller层
     * @author: wl.ding
     * @create: 2020-06-27 15:15
     **/
    public class Controller {
    
        private Service service;  //将service注入进来
    
        public Service getService() {
            return service;
        }
    
        public void setService(Service service) {
            this.service = service;
        }
    }
    
    

    将Service对象注入Controller中

    package com.company.Spring;
    
    import java.lang.reflect.Field;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    
    /**
     * @program: demo
     * @description: 测试类
     * @author: wl.ding
     * @create: 2020-06-27 15:16
     **/
    public class Test {
    
        public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
            Controller controller = new Controller();
            Service service = new Service() ;
    
            //通过反射完成注入功能
            Class<? extends Controller> clazz = controller.getClass();
            //获取属性
            Field serviceField = clazz.getDeclaredField("service");
            //设置访问属性因为Controller中的属性为私有属性
             serviceField.setAccessible(true);
             //获取对应的set方法
            String name = serviceField.getName(); //此时获取的是service 我们需要获取的是setService因此需要拼接
            name = name.substring(0,1).toUpperCase()+name.substring(1,name.length()); //获取的是Service
    
            String methodName = "set" + name;
            //第一个参数为要获取的方法的名称
            //第二个为要获取方法的参数的类型,参数为 Class...,没有参数就是null
            Method method = clazz.getMethod(methodName,Service.class);
    
            //调用setService方法
            //controller 要操作的对象
            //后面参数为传实参
            method.invoke(controller,service);
            //此时输出的两个对象应该相同
            System.out.println(controller.getService());
            System.out.println(service);
        }
    }
    
    
    展开全文
  • 或者通过反射来创建对象,然后调用目标类的方法时,此时目标类如果也依赖注入了其他的bean。那么此时所有的bean都会脱离spring容器的管理。我们的方法中就会报错【java.lang.NullPointerException】那么我们改如何...
  • PHP反射机制实现自动依赖注入

    万次阅读 多人点赞 2017-04-13 15:21:42
    依赖注入又叫控制反转,使用过框架的人应该都不陌生。很多人一看名字就觉得是非常高大上的东西,就对它望而却步,今天抽空研究了下,解开他它的神秘面纱。
  • 主要介绍了PHP类的反射来实现依赖注入过程以及相关知识点分享,对此有兴趣的朋友跟着小编学习下吧。
  • 主要介绍了PHP基于反射机制实现自动依赖注入的方法,结合实例形式分析了php使用反射实现自动依赖注入的步骤、原理与相关操作技巧,需要的朋友可以参考下
  • 主要介绍了php反射学习之依赖注入,结合具体实例形式分析了php基于反射依赖注入原理与实现方法,需要的朋友可以参考下
  • 什么是IOC容器,什么是依赖注入。 我的不严谨的个人理解及其的抽象: 把IOC容器可以理解为图书馆,我们图书馆进行放书的时候,相当于就是注册服务。这个服务可以是接口,也可以是对象,接口也可以从另一个纬度...
  • 反射依赖注入DEMO

    2015-07-10 11:08:37
    最近在熟悉反射依赖注入,特意写了一下简单的实例,希望可以帮助到你我他
  • 主要介绍了JavaScript反射依赖注入,结合实例形式较为详细的分析了JavaScript反射依赖注入的概念、原理、定义、使用方法及相关操作注意事项,需要的朋友可以参考下
  • 发现没问题, 百度了一下,发现了有个问题:拦截器加载的时间点在springcontext之前,所以在拦截器中注入自然为null 根据解决方法在配置拦截器链的类中先注入这个拦截器,代码如下: package com.***; import org....
  • :hammer:dig基于Go的基于反射依赖注入工具包。 优点:为应用程序框架(例如Fx)提供动力。 在流程启动期间解析对象图。 :hammer:dig基于Go的基于反射依赖注入工具包。 优点:为应用程序框架(例如Fx)提供动力。...
  • php 反射 依赖注入

    2017-05-04 15:29:22
    php 反射 依赖注入
  • 依赖注入 在一个类中经常会依赖于其他的对象,先看一下经典的写法 class Foo { public $bar; public function __construct() { $this->bar = new Bar(); } } $foo = new Foo(); 当类的依赖发生改变时...
  • 这样带来的一个问题是,如果有模块要修改,势必会影响其他模块,如果模块很多,还需要人为的规定初始化顺序,这对大型项目的维护来说是一件很恐怖的事,因此依赖注入的引入可以减少维护依赖关系的精力,专心使开
  • 类的反射依赖注入

    2018-05-21 10:48:21
    在讲服务容器之前我想先梳理下PHP反射相关的知识,PHP反射是程序实现依赖注入的基础,也是Laravel的服务容器实现服务解析的基础,如果你已经掌握了这方面基础知识,那么可以跳过本文直接看服务容器部分的内容。...
  • Spring 反射调用包含依赖注入的方法样例 什么都不说直接上代码 public class BackRequestServiceImpl implements ApplicationContextAware { @Autowired private ServiceConduitService serviceConduitService; ...
  • dig一个用于Go语言基于反射依赖注入工具包
  • 在使用laravel的时候,...依赖注入使用PHP反射API实现 反射机制被多种语言使用,用来获取类、实例对象、方法等语言构件信息,通过反射API函数可以动态进行操作。以下编写了简单的例子来说明。我们需要调用App::run...
  • 简书上的这篇文章感觉讲的挺好的,不过最后两个注解和依赖注入讲的有点宽泛,不知是不是我理解能力不行O__O "… 文章链接http://www.jianshu.com/p/24820bf3df5c
  • Spring Bean 应该是Spring被使用最多的功能 ,通过注解/xml配置 ,可以简化大量的依赖...依赖注入依赖注入 ,也就是所依赖的对象不由自己处理 ,而是由外部系统去分配 .就像排队取餐时 ,不是每个人自己去盛菜 ,而是告诉服
  • 一个简单的依赖注入容器(一个简单的依赖注入容器) 初衷 实习时导师要求我研究一下依赖注入容器并试着自己手写一个,我一听,好家伙,又是加班的一天啊。 当时用的是C#,就翻了翻IServiceCollection的二进制文件,...
  • 2、依赖注入(DI):不是由自己内部new对象或者实例,而是通过构造函数或方法传入调用其他类的都属于依赖注入 。 原始代码 控制反转和依赖注入 左边的问题:...
  • 本文意于让人简单地使用注解跟反射,用注解让控件实现findViewById()以及setOnClickListener(),不再重复写findViewById这些重复性的工作。 市面上已经有很多这种框架,比如xUtils,Butterknife等,浅略地看了这两个...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 61,717
精华内容 24,686
关键字:

反射依赖注入