IOC容器是一个管理Bean的容器,它要求所有的Bean都需要实现接口
    BeanFactory是一个顶级的容器接口

    BeanFactory.class 源码

    1. public interface BeanFactory {
    2. String FACTORY_BEAN_PREFIX = "&";
    3. //获取Bean
    4. Object getBean(String var1) throws BeansException;
    5. <T> T getBean(String var1, Class<T> var2) throws BeansException;
    6. Object getBean(String var1, Object... var2) throws BeansException;
    7. <T> T getBean(Class<T> var1) throws BeansException;
    8. <T> T getBean(Class<T> var1, Object... var2) throws BeansException;
    9. //获取Bean的提供者
    10. <T> ObjectProvider<T> getBeanProvider(Class<T> var1);
    11. <T> ObjectProvider<T> getBeanProvider(ResolvableType var1);
    12. //是否包含该Bean
    13. boolean containsBean(String var1);
    14. //是否是单例
    15. boolean isSingleton(String var1) throws NoSuchBeanDefinitionException;
    16. //是否是原型
    17. boolean isPrototype(String var1) throws NoSuchBeanDefinitionException;
    18. //是否类型匹配
    19. boolean isTypeMatch(String var1, ResolvableType var2) throws NoSuchBeanDefinitionException;
    20. boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException;
    21. //获取类型
    22. @Nullable
    23. Class<?> getType(String var1) throws NoSuchBeanDefinitionException;
    24. //获取别名
    25. String[] getAliases(String var1);
    26. }

    从上面可以结合中文注释可以看出 BeanFactory中提供的方法的一些作用

    • isSingleton 判断这个Bean是否是单例的,默认情况下容器中的Bean都是单例的
    • isPrototype 和isSingleton的相反,如果返回true每次从容器当中获取一个Bean都是重新创建
    • BeanFactory提供的方法是一些常用的对Bean获取方法,但是工作中可能我们的需求更大所以需要更多。在此之上也提供了一个更高级的注解ApplicationContext 在使用IOC容器的时候,大部分类都实现来自己 ApplicationCOntext接口。

    演示框架采用SpringBoot最新版本

    @Data
    public class Users {
    
        private Integer id;
    
        private String userName;
    
        private String userId;
    
        public Users(Builder builder) {
            id = builder.id;
            userId = builder.userId;
            userName = builder.userName;
        }
    
        //Builder构造器模式
        public static class Builder {
            int id;
    
            String userName;
    
            String userId;
    
            public Builder(int id, String userName, String userId) {
                this.id = id;
                this.userName = userName;
                this.userId = userId;
            }
    
            public Builder id(int id) {
                this.id = id;
                return this;
            }
    
            public Builder userName(String userName) {
                this.userName = userName;
                return this;
            }
    
            public Builder userId(String userId) {
                this.userId = userId;
                return this;
            }
    
            public Users builder() {
                return new Users( this );
            }
        }
    }
    

    上面采用构造器模式 原因只是 个人想复习一下 没有其他想表达的意思,望别误入

    //表示一个配置文件
    @SuppressWarnings("ALL")
    @Configuration
    public class ApplicationConfig {
    
        //表示声明一个user的Bean如果没有user那么会直接采用方法名作为这个Bean的名称
        @Bean("user")
        public Users initUser() {
            Users users = new Users.Builder( 1, "zhangsan", "lucy" ).builder();
    //        Users users=new Users(  );
    //        users.setId( 1 );
    //        users.setUserName( "张三" );
    //        users.setUserId( "Lucy" );
            return users;
        }
    }
    

    测试

    public class IocTest {
        //SpringBoot自带日志
        private static Logger logger= LoggerFactory.getLogger( IOContext.class );
        public static void main(String[] args) {
            ApplicationContext applicationContext =
                    new AnnotationConfigApplicationContext(
                            ApplicationConfig.class );
            Users bean = applicationContext.getBean( Users.class );
    
            logger.debug( bean.toString() );
        }
    }
    
    14:57:17.223 [main] DEBUG com.fasterxml.jackson.core.io.IOContext - Users(id=1, userName=zhangsan, userId=lucy)
    

    我们可以通过第一种方式加载Bean
    还可以通过扫描的方式加载Bean
    采用SpringBoot的ComponentScan 扫描 不多BB直接看源码 用法 自行百度

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.TYPE})
    @Documented
    @Repeatable(ComponentScans.class)
    public @interface ComponentScan {
       //定义扫描的包
        @AliasFor("basePackages")
        String[] value() default {};
    
    
        //扫描包路径  默认扫描当前包以及他的子包
        @AliasFor("value")
        String[] basePackages() default {};
    
        //定义扫描的类
        Class<?>[] basePackageClasses() default {};
          //BeanName生成器
        Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
        //作用域解析器
        Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;
        //作用域代理器
        ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;
        //资源匹配模式
        String resourcePattern() default "**/*.class";
      //是否启用默认过滤 默认true
        boolean useDefaultFilters() default true;
        //满足条件扫描                不满足的时候不扫描
        ComponentScan.Filter[] includeFilters() default {};
         当不满足条件时间扫描   满足的时候 过滤
        ComponentScan.Filter[] excludeFilters() default {};
         //是否延迟加载 默认为false
        boolean lazyInit() default false;
    
        @Retention(RetentionPolicy.RUNTIME)
        @Target({})
        public @interface Filter {
            FilterType type() default FilterType.ANNOTATION;
    
            @AliasFor("classes")
            Class<?>[] value() default {};
    
            @AliasFor("value")
            Class<?>[] classes() default {};
    
            String[] pattern() default {};
        }
    }
    
    IoC 的三个经典问题
    对于 IoC 有三个经典问题:谁控制谁?控制了什么?怎么实现了反转?很多博客里都进行了一个回答,笔者也按照自己的故事模式进行一个回答。
    * “谁控制谁?”:IoC / DI 容器控制应用程序
    * 控制了什么?:IoC / DI 容器控制对象本身的创建、实例化,以及控制对象之间的依赖关系;
    * 开发之中的对象已经全部交由 IoC 容器来管理了,那我们在获取对象的时候,就得由 IoC 容器来给我们提供;
    2.3 DI 的三个经典问题
    * “谁依赖谁?”:应用程序依赖于 IoC 容器;
    * “谁注入了谁?”:IoC 容器把对象注入于应用程序;
    * “注入了什么?”:注入应用程序需要的外部资源,比如有依赖关系的对象