Spring注解驱动之注册组件(spring的再回顾)
一. 组件注册
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的再回顾)相关推荐
- 0、Spring 注解驱动开发
0.Spring注解驱动开发 0.1 简介 <Spring注解驱动开发>是一套帮助我们深入了解Spring原理机制的教程: 现今SpringBoot.SpringCloud技术非常火热,作 ...
- 【Spring注解驱动开发】使用@Scope注解设置组件的作用域
写在前面 Spring容器中的组件默认是单例的,在Spring启动时就会实例化并初始化这些对象,将其放到Spring容器中,之后,每次获取对象时,直接从Spring容器中获取,而不再创建对象.如果每次 ...
- Spring注解驱动开发第26讲——总有人让我给他讲讲@EnableAspectJAutoProxy注解
@EnableAspectJAutoProxy注解 在配置类上添加@EnableAspectJAutoProxy注解,便能够开启注解版的AOP功能.也就是说,如果要使注解版的AOP功能起作用的话,那么 ...
- 【Spring注解驱动开发】二狗子让我给他讲讲@EnableAspectJAutoProxy注解
写在前面 最近,二狗子入职了新公司,新入职的那几天确实有点飘.不过慢慢的,他发现他身边的人各个身怀绝技啊,有Spring源码的贡献者,有Dubbo源码的贡献者,有MyBatis源码的贡献者,还有研究A ...
- SPRING注解驱动开发-雷神课程超详细笔记
SPRING注解驱动开发-雷神课程超详细笔记 时间:2021-03-21 2022-04-06更新:最近翻起一年多前写的笔记复习,还是收获颇多,很多当时无法理解的知识现在慢慢能理解了,可能是工作一年的 ...
- spring注解驱动开发-10 Servlet3.0
Spring AOP实现 前言 servlet3.0简介 ServletContainerInitializer shared libraries(共享库) / runtimes pluggabili ...
- spring注解驱动开发-8 Spring 扩展原理
Spring 扩展原理 前言 BeanFactoryPostProcessor 测试实例编写 ExtConfig MyBeanFactoryPostProcessor ExtTest 源码分析 Bea ...
- spring注解驱动开发-4 Spring 自动装配
Spring 自动装配 前言 Spring 自动装配的几种方式 1.@Autowired @Qualifier("组件id") @Primary 2.@Resource方式 3.@ ...
- spring注解驱动开发-7 Spring声明式事务
Spring 声明式事务 前言 @EnableTransactionManagement AutoProxyRegistrar InfrastructureAdvisorAutoProxyCreato ...
最新文章
- C++:名字空间的使用
- nginx lua redis 访问频率限制(转)
- Python 3下Matplotlib画图中文显示乱码的解决方法
- Java-P: 2_3,类成员具有的控制修饰符
- CocoaPods的安装[转载]
- centos7修改服务器密码忘记,Centos7忘记root密码怎么修改
- 阿里云数据库mysql 创建数据库服务器_如何使用mysql创建数据库服务器
- 开发一个大型后台管理系统,真的需要用前后端分离的技术方案吗?
- python idle是什么_下载下来的IDLE是个什么鬼
- 机器学习中应用到的各种距离介绍(附上Matlab代码)
- idea redis 插件_Redis客户端RDM收费后,还有那些开源的替代品呢?
- Servlet JSP - 转发与重定向的区别
- linux下最常见的操作和命令
- 高德地图使用-高亮省市区
- uniapp商城前端源码下载/uniapp多店铺PHP商城源码下载
- 论文评审最大流_2018年论文评审流程
- CNN中为什么普遍使用小卷积核
- 多线程【全面学习 图文精讲】
- c#,c++,qt中多线程访问UI控件线程的问题汇总
- [微语20.12.01] 心静
热门文章
- 高新技术企业认定条件
- Android 原生控件之三 ProgressBar
- 【第148期】游戏策划:恭喜@灯入职剧情策划
- Mixly(米思齐)的安装以及实现光控小夜灯
- EST | 西湖大学鞠峰组提出表型宏基因组学用于超广谱抗生素耐药组的高通量环境检测...
- 用Assimp模型加载库加载一个Crytek的游戏孤岛危机(Crysis)中的原版纳米装(Nanosuit)
- LBS AR开发实录(1):手机位姿数据的实时获取
- Games104 Lecture 7 游戏中渲染管线、后处理和其他的一切
- 一文带你了解200G DAC高速线缆
- 微信公众开发URL和token填写详解