一. 组件注册

1. 给容器中注册组件

xml方式

  • 创建一个实体类(构造方法等省略)

    public class Person {private String name;private Integer age;}
    
  • resources资源目录下创建xml文件

    • 利用bean标签注册一个组件
    • 得到id,方便从容器中获取该bean
    • 使用property进行属性赋值
    <bean id="person" class="com.lcy.bean.Person"><property name="name" value="诸葛亮"/><property name="age" value="18"/>
    </bean>
    
  • 创建一个测试类

    • 传入配置文件的位置,返回IOC容器
    • 根据id获取值
        @Testpublic void t1() {// new一个CPXAC传入配置文件的位置,返回IOC容器applicationContextApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");// 根据id获取组件Person person = (Person) applicationContext.getBean("person");System.out.println(person);}
    
  • 控制台输出

    Person{name='诸葛亮', age=18}
    

配置类方式

  • 实体类不变

  • 创建一个配置类

    // 配置类==配置文件
    @Configuration  // 告诉Spring这是一个配置类
    public class MainConfig {// 给容器注册一个Bean,类型为返回值的类型,id默认是方法名(可以直接指定value方法值)@Beanpublic Person person() {return new Person("刘备",19);}}
    
  • 测试类(入口代码省略)

        @Testpublic void t2() {// new一个AnnotationConfigApplicationContext,传入配置文件,得到IOC容器ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);// 根据类型获取值Person bean = applicationContext.getBean(Person.class);System.out.println("根据类型获取"+bean);// 根据Id获取,默认Id就是方法名String[] namesForType = applicationContext.getBeanNamesForType(Person.class);for (String name : namesForType) {System.out.println("获取该组件的id是"+name);}}
    
  • 控制台

    根据类型获取Person{name='刘备', age=19}
    获取该组件的id是person
    

2. 自动扫描组件与指定扫描规则

xml文件扫描时

  • 在配置文件中配置

    • 只要指定包下的标注了Controller,Service,Repository,Component就会被扫描到
    <context:component-scan base-package="com.lcy"/>
    

配置文件包扫描

  • 在配置类上加上注解@ComponentScan

    // 配置类==配置文件
    @ComponentScan(value = "com.lcy")   // 包扫描
    @Configuration  // 告诉Spring这是一个配置类
    public class MainConfig {@Beanpublic Person person() {return new Person("刘备",19);}
    }
    
  • 测试

    • 获取当前IOC中所有组件的名字
    @Test
    public void t3() {ApplicationContext ioc = new AnnotationConfigApplicationContext(MainConfig.class);// 获取容器中所有组件的名字String[] names = ioc.getBeanDefinitionNames();for (String name : names) {System.out.println(name);}
    }
    
  • 控制台

    org.springframework.context.annotation.internalConfigurationAnnotationProcessor
    org.springframework.context.annotation.internalAutowiredAnnotationProcessor
    org.springframework.context.annotation.internalCommonAnnotationProcessor
    org.springframework.context.event.internalEventListenerProcessor
    org.springframework.context.event.internalEventListenerFactory
    mainConfig
    personController
    personDao
    personService
    person
    
  • excludeFilters(排除)

  • 排除Controller和Service标注的组件

```Java
@ComponentScan(value = "com.lcy",excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class, Service.class})})
@Configuration
public class MainConfig {@Beanpublic Person person() {return new Person("刘备",19);}}
```
  • 控制台

    • 与上次输出比较,过滤规则起作用了
    org.springframework.context.annotation.internalConfigurationAnnotationProcessor
    org.springframework.context.annotation.internalAutowiredAnnotationProcessor
    org.springframework.context.annotation.internalCommonAnnotationProcessor
    org.springframework.context.event.internalEventListenerProcessor
    org.springframework.context.event.internalEventListenerFactory
    mainConfig
    personDao
    person
    
  • includeFilters(只包含)

    • 恰恰相反,需要禁用掉默认过滤规则才能生效

      • useDefaultFilters = false
        
    • 只要Controller和Service标注的组件

    @ComponentScan(value = "com.lcy",includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class, Service.class})},useDefaultFilters = false)
    @Configuration
    public class MainConfig {@Beanpublic Person person() {return new Person("刘备",19);}
    }
    
    • 控制台

      org.springframework.context.annotation.internalConfigurationAnnotationProcessor
      org.springframework.context.annotation.internalAutowiredAnnotationProcessor
      org.springframework.context.annotation.internalCommonAnnotationProcessor
      org.springframework.context.event.internalEventListenerProcessor
      org.springframework.context.event.internalEventListenerFactory
      mainConfig
      personController
      personService
      person
      

扫描规则

@ComponentScan(value = "com.lcy",includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class, Service.class}),@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = PersonDao.class)},useDefaultFilters = false)
// @ComponentScan  value:指定要扫描的包
// includeFilters = Filter[]:指定扫描时只需要包含哪些组件
// excludeFilters = Filter[]:指定扫描时按照规则排除组件
// FilterType.ANNOTATION:按照注解(常用)
// FilterType.ASSIGNABLE_TYPE:按照类型(常用)所有的其子类实现类都会被加载进来
// FilterType.ASPECTJ:按照ASPECTJ表达式
// FilterType.REGEX:按照正ava则
// FilterType.CUSTOM:按照自定义规则(需要TypeFilter的实现类)
  • 自定义过滤规则

    • 创建一个类实现TypeFilter接口

      public class MyTypeFilter implements TypeFilter {/**** @param metadataReader            读取到的当前正在扫描类的信息* @param metadataReaderFactory     可以读取到其他任何类的信息* @return* @throws IOException*/@Overridepublic boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {// 获取当前类注解的信息AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();// 获取当前正在扫描类的类信息(比如实现了什么接口,什么类型)ClassMetadata classMetadata = metadataReader.getClassMetadata();// 获取当前类资源(类的路径)Resource resource = metadataReader.getResource();// 获取当前正在处理类的类名String className = classMetadata.getClassName();System.out.println("----->类名"+className);// 如果类名中包含Dao,则返回true,匹配成功放行if (className.contains("Dao")) {return true;}return false;}}
      
    • 配置类进行设置

      @Configuration
      @ComponentScan(value = "com.lcy",includeFilters = {@ComponentScan.Filter(type = FilterType.CUSTOM,classes = MyTypeFilter.class)},                      // 自定义规则useDefaultFilters = false)
      public class MainConfig {@Beanpublic Person person() {javareturn new Person("刘备",19);}
      }
      
    • 控制台

      ----->类名com.lcy.bean.Person
      ----->类名com.lcy.config.MyTypeFilter
      ----->类名com.lcy.controller.PersonController
      ----->类名com.lcy.dao.PersonDao
      ----->类名com.lcy.service.PersonService
      org.springframework.context.annotation.internalConfigurationAnnotationProcessor
      org.springframework.context.annotation.internalAutowiredAnnotationProcessor
      org.springframework.context.annotation.internalCommonAnnotationProcessor
      org.springframework.context.event.internalEventListenerProcessor
      org.springframework.context.event.internalEventListenerFactory
      mainConfig
      personDao
      personProcess finished with exit code 0

3. @Scope设置作用域

默认单例

  • 配置类

    @Configuration
    public class MainConfig2 {// 默认为单例/*** prototype:多实例的* singleton:单实例的(默认值)ioc容器每次调用方法创建对象放到ioc容器中*                  之后的每一次获取都是直接从容器中拿* request:  同一次请求创建一个实例(需要web环境)* session:   同一个Session创建一个实例(需要web环境)*/@Scope@Beanpublic Person person() {System.out.println("给容器添加Person");return new Person("周瑜",20);}}
    
  • 测试类

    @Test
    public void t4() {ApplicationContext ioc = new AnnotationConfigApplicationContext(MainConfig2.class);// 根据Id来获取Person bean1 = (Person) ioc.getBean("person");Person bean2 = (Person) ioc.getBean("person");// 默认单例,判断两个对象是否相等System.out.println(bean1 == bean2); // true}
    
  • 控制台

    给容器添加Person
    IOC容器创建完成
    true
    

多例

  • 配置类

    @Configuration
    public class MainConfig2 {@Bean/*** prototype:多实例的:ioc启动并不会创建对象放在容器*                   每次获取时才会调用方法创建对象*/@Scope("prototype")public Person person() {System.out.println("给容器添加Person");return new Person("周瑜",20);}
    }
    
  • 测试类

        @Testpublic void t4() {ApplicationContext ioc = new AnnotationConfigApplicationContext(MainConfig2.class);System.out.println("IOC容器创建完成");// 根据Id来获取Person bean1 = (Person) ioc.getBean("person");Person bean2 = (Person) ioc.getBean("person");// 修改为prototype,判断两个对象是否相等System.out.println(bean1 == bean2); // false}
    
  • 控制台

    IOC容器创建完成
    给容器添加Person
    给容器添加Person
    false
    

懒加载

  • 配置类(未启动懒加载)

    @Configuration
    public class MainConfig2 {// 默认为单例@Bean/*** singleton:单实例的(默认值)ioc容器每次调用方法创建对象放到                  ioc容器中* 懒加载:*      单实例Bean:默认在容器启动时创建对象*      懒加载:容器启动时不创建对象,第一次(使用)获取Bean创建              对象并初始化**/@Scopepublic Person person() {System.out.println("给容器添加Person");return new Person("周瑜",20);}
    }
    
  • 测试类

        @Testpublic void t4() {ApplicationContext ioc = new AnnotationConfigApplicationContext(MainConfig2.class);System.out.println("IOC容器创建完成");}
    
  • 控制台

    • 在IOC启动的时候就创建完成了
    给容器添加Person
    IOC容器创建完成
    
  • 启用懒加载@Lazy

    • 配置类

      @Configuration
      public class MainConfig2 {@Bean@Scope@Lazypublic Person person() {System.out.println("给容器添加Person");return new Person("周瑜",20);}
      }
      
    • 测试类与控制台(未使用Bean)

          @Testpublic void t4() {ApplicationContext ioc = new AnnotationConfigApplicationContext(MainConfig2.class);System.out.println("IOC容器创建完成");}
      
      IOC容器创建完成
      
    • 测试类与控制台(使用Bean)

      • 使用Bean时才会创建,并且只会创建一次
          @Testpublic void t4() {ApplicationContext ioc = new AnnotationConfigApplicationContext(MainConfig2.class);System.out.println("IOC容器创建完成");// 根据Id来获取Person bean1 = (Person) ioc.getBean("person");Person bean2 = (Person) ioc.getBean("person");}
      
      IOC容器创建完成
      给容器添加Person
      

4. @Conditional按照条件注册bean

  • 若放在类上,必须满足条件,此类中的bean注册才能生效

  • 条件:

    • 如果是windows,给容器中注册windows
    • 如果是Linux,给容器中注册Linux
  • 配置类

    /*** @return* @Conditional({}) :按照一定条件进行判断,满足条件给容器中注册            bean*/
    @Conditional({WindowsCondition.class})  // 放在类上,必须满足条件,此类中的bean注册才能生效
    @Bean("Windows")
    public Person person1() {return new Person("Windows", 22);
    }@Bean("Linux")
    @Conditional({LinuxCondition.class})
    public Person person2() {return new Person("Linux", 20);
    }
    
  • 分别创建两个类实现Condition接口

    // 判断是否为Linux系统
    public class LinuxCondition implements Condition {@Overridepublic boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {Environment environment = conditionContext.getEnvironment();String property = environment.getProperty("os.name");if (property.contains("Linux")) {return true;}return false;}java
    }
    
    // 判断是否为Windows系统
    public class WindowsCondition implements Condition {/**** @param conditionContext      判断条件能使用的上下文环境* @param annotatedTypeMetadata 注释信息* @return*/@Overridepublic boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {// 1.能获取到IOC使用的beanfactoryConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();// 2.获取类加载器ClassLoader classLoader = conditionContext.getClassLoader();// 3.获取当前环境信息Environment environment = conditionContext.getEnvironment();// 4.获取到bean定义的注册类BeanDefinitionRegistry registry = conditionContext.getRegistry();// 可以判断容器中的bean注册情况,也可以给容器中注册beanboolean person = registry.containsBeanDefinition("person");// 获取操作系统String property = environment.getProperty("os.name");// 判断是否为Windows系统if (property.contains("Windows")){return true;}return false;}
    }
    
  • 测试类

    @Test
    public void t5() {ApplicationContext ioc = new AnnotationConfigApplicationContext(MainConfig2.class);String[] beanNamesForType = ioc.getBeanNamesForType(Person.class);for (String name : beanNamesForType) {System.out.println(name);}Map<String, Person> personMap = ioc.getBeansOfType(Person.class);System.out.println(personMap);}
    
  • 控制台

    • 因为是Windows操作系统,所以Linux并没有注册进来
    • person是之前已注册的
    person
    Windows
    给容器添加Person
    {person=Person{name='周瑜', age=20}, Windows=Person{name='Windows', age=22}}
    

5. @Import导入组件

@Import

  • 创建一个实体类

    public class Color {}
    
  • 配置类加入类名@Import

    @Configuration
    @Import(Color.class)
    //@Import({Color.class, Person.class}) 也可以导多个类
    public class MainConfig3 {/*** 给容器中注册组件:* 1.包扫描+组件标注注解(@Controller,@Service,@Repository,@Component)[局限于自己创建的类]* 2.@Bean[导入的第三方包里面的组件]* 3.@Import[快速给容器中导入一个组件]*      1.@Improt(要导入容器的组件),容器会自动注册这个组件,id默认是全类名*/}
    
  • 测试类

    @Test
    public void t6() {ApplicationContext ioc = new AnnotationConfigApplicationContext(MainConfig3.class);String[] names = ioc.getBeanDefinitionNames();for (String name : names) {System.out.println(name);}}
    
  • 控制台

    org.springframework.context.annotation.internalConfigurationAnnotationProcessor
    org.springframework.context.annotation.internalAutowiredAnnotationProcessor
    org.springframework.context.annotation.internalCommonAnnotationProcessor
    org.springframework.context.event.internalEventListenerProcessor
    org.springframework.context.event.internalEventListenerFactory
    mainConfig3
    com.lcy.bean.Color
    

ImportSelector接口

  • 创建一个类实现ImportSelector接口

    // 自定义逻辑返回需要导入的组件
    public class MyImportSelector implements ImportSelector {/*** 返回值就是要导入到容器中的组件全类名* @param annotationMetadata    :当前标注@Import注解类的所有注解信息* @return*/@Overridepublic String[] selectImports(AnnotationMetadata annotationMetadata) {// 放入需要注册组件的全类名return new String[]{"com.lcy.bean.Red","com.lcy.bean.Blue"};}
    }
    
  • 配置类

    @Configuration
    @Import({Color.class, MyImportSelector.class})
    public class MainConfig3 {/*** ImportSelector:返回需要导入的组件的全类名数组*    创建一个类实现ImportSelector接口,在@Import上导入*/}
    
  • 测试(代码如上不变)控制台

    org.springframework.context.annotation.internalConfigurationAnnotationProcessor
    org.springframework.context.annotation.internalAutowiredAnnotationProcessor
    org.springframework.context.annotation.internalCommonAnnotationProcessor
    org.springframework.context.event.internalEventListenerProcessor
    org.springframework.context.event.internalEventListenerFactory
    mainConfig3
    com.lcy.bean.Color
    com.lcy.bean.Red
    com.lcy.bean.Blue
    

ImportBeanDefinitionRegistrar接口

  • 创建新的实体类

    public class RainBow {}
    
  • 配置类

    @Configuration
    @Import({Color.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
    public class MainConfig3 {/*** ImportBeanDefinitionRegistrar:手动注册bean到容器*/}
    
  • 创建一个类实现ImportBeanDefinitionRegistrar接口

    public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {/**** @param importingClassMetadata:当前类的注解信息* @param registry              : 把所有需要添加到容器中的bean,*                              调用registry.registerBeanDefinition手工注册进来*/@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {// 指定bean的定义信息(Bean的类型)RootBeanDefinition beanDefinition = new RootBeanDefinition(RainBow.class);// 注册一个bean,指定bean名registry.registerBeanDefinition("rainBow",beanDefinition);}
    }
    
  • 测试类(代码不变)与控制台

    org.springframework.context.annotation.internalConfigurationAnnotationProcessor
    org.springframework.context.annotation.internalAutowiredAnnotationProcessor
    org.springframework.context.annotation.internalCommonAnnotationProcessor
    org.springframework.context.event.internalEventListenerProcessor
    org.springframework.context.event.internalEventListenerFactory
    mainConfig3
    com.lcy.bean.Color
    com.lcy.bean.Red
    com.lcy.bean.Blue
    rainBow
    

FactoryBean工厂Bean

  • 配置类

    /*** .使用Spring提供的FactoryBean(工厂Bean)*      1.默认获取到的是工厂Bean调用getObject创建的对象*      2.要获取工厂Bean本身,则在id前加一个&*/
    @Bean   // 虽然注册的是YellowFactoryBean,但实际上是Yellow
    public YellowFactoryBean yellowFactoryBean() {return new YellowFactoryBean();
    }
    
  • 创建一个实体类

    public class Yellow {
    }
    
  • 创建一个类实现FactoryBean接口

    public class YellowFactoryBean implements FactoryBean<Yellow> {// 返回一个Yellow对象,这个对象会添加到容器中@Overridepublic Yellow getObject() throws Exception {System.out.println("YellowFactoryBean。。。。。getObject");return new Yellow();}// 返回对象的类型@Overridepublic Class<?> getObjectType() {return Yellow.class;}// 控制是否单例:true为单例; 在容器中保存一份// false:多例;每次获取都会创建一个新的bean,获取的时候会调用getObject@Overridepublic boolean isSingleton() {return true;}
    }
    
  • 测试类

    @Test
    public void t6() {ApplicationContext ioc = new AnnotationConfigApplicationContext(MainConfig3.class);// 工厂Bean获取的是调用gerObject创建的对象Object bean = ioc.getBean("yellowFactoryBean");System.out.println("bean的类型="+bean.getClass());// 若想获取工厂Bean的本身则加&Object bean1 = ioc.getBean("&yellowFactoryBean");System.out.println("bean的类型="+bean1);}
    
  • 控制台

    YellowFactoryBean。。。。。getObject
    bean的类型=class com.lcy.bean.Yellow
    bean的类型=com.lcy.condition.YellowFactoryBean@1f0f1111
    

Spring注解驱动之注册组件(spring的再回顾)相关推荐

  1. 0、Spring 注解驱动开发

    0.Spring注解驱动开发 0.1 简介 <Spring注解驱动开发>是一套帮助我们深入了解Spring原理机制的教程: 现今SpringBoot.SpringCloud技术非常火热,作 ...

  2. 【Spring注解驱动开发】使用@Scope注解设置组件的作用域

    写在前面 Spring容器中的组件默认是单例的,在Spring启动时就会实例化并初始化这些对象,将其放到Spring容器中,之后,每次获取对象时,直接从Spring容器中获取,而不再创建对象.如果每次 ...

  3. Spring注解驱动开发第26讲——总有人让我给他讲讲@EnableAspectJAutoProxy注解

    @EnableAspectJAutoProxy注解 在配置类上添加@EnableAspectJAutoProxy注解,便能够开启注解版的AOP功能.也就是说,如果要使注解版的AOP功能起作用的话,那么 ...

  4. 【Spring注解驱动开发】二狗子让我给他讲讲@EnableAspectJAutoProxy注解

    写在前面 最近,二狗子入职了新公司,新入职的那几天确实有点飘.不过慢慢的,他发现他身边的人各个身怀绝技啊,有Spring源码的贡献者,有Dubbo源码的贡献者,有MyBatis源码的贡献者,还有研究A ...

  5. SPRING注解驱动开发-雷神课程超详细笔记

    SPRING注解驱动开发-雷神课程超详细笔记 时间:2021-03-21 2022-04-06更新:最近翻起一年多前写的笔记复习,还是收获颇多,很多当时无法理解的知识现在慢慢能理解了,可能是工作一年的 ...

  6. spring注解驱动开发-10 Servlet3.0

    Spring AOP实现 前言 servlet3.0简介 ServletContainerInitializer shared libraries(共享库) / runtimes pluggabili ...

  7. spring注解驱动开发-8 Spring 扩展原理

    Spring 扩展原理 前言 BeanFactoryPostProcessor 测试实例编写 ExtConfig MyBeanFactoryPostProcessor ExtTest 源码分析 Bea ...

  8. spring注解驱动开发-4 Spring 自动装配

    Spring 自动装配 前言 Spring 自动装配的几种方式 1.@Autowired @Qualifier("组件id") @Primary 2.@Resource方式 3.@ ...

  9. spring注解驱动开发-7 Spring声明式事务

    Spring 声明式事务 前言 @EnableTransactionManagement AutoProxyRegistrar InfrastructureAdvisorAutoProxyCreato ...

最新文章

  1. C++:名字空间的使用
  2. nginx lua redis 访问频率限制(转)
  3. Python 3下Matplotlib画图中文显示乱码的解决方法
  4. Java-P: 2_3,类成员具有的控制修饰符
  5. CocoaPods的安装[转载]
  6. centos7修改服务器密码忘记,Centos7忘记root密码怎么修改
  7. 阿里云数据库mysql 创建数据库服务器_如何使用mysql创建数据库服务器
  8. 开发一个大型后台管理系统,真的需要用前后端分离的技术方案吗?
  9. python idle是什么_下载下来的IDLE是个什么鬼
  10. 机器学习中应用到的各种距离介绍(附上Matlab代码)
  11. idea redis 插件_Redis客户端RDM收费后,还有那些开源的替代品呢?
  12. Servlet JSP - 转发与重定向的区别
  13. linux下最常见的操作和命令
  14. 高德地图使用-高亮省市区
  15. uniapp商城前端源码下载/uniapp多店铺PHP商城源码下载
  16. 论文评审最大流_2018年论文评审流程
  17. CNN中为什么普遍使用小卷积核
  18. 多线程【全面学习 图文精讲】
  19. c#,c++,qt中多线程访问UI控件线程的问题汇总
  20. [微语20.12.01] 心静

热门文章

  1. 高新技术企业认定条件
  2. Android 原生控件之三 ProgressBar
  3. 【第148期】游戏策划:恭喜@灯入职剧情策划
  4. Mixly(米思齐)的安装以及实现光控小夜灯
  5. EST | 西湖大学鞠峰组提出表型宏基因组学用于超广谱抗生素耐药组的高通量环境检测...
  6. 用Assimp模型加载库加载一个Crytek的游戏孤岛危机(Crysis)中的原版纳米装(Nanosuit)
  7. LBS AR开发实录(1):手机位姿数据的实时获取
  8. Games104 Lecture 7 游戏中渲染管线、后处理和其他的一切
  9. 一文带你了解200G DAC高速线缆
  10. 微信公众开发URL和token填写详解