1.配置组件(Configure Components)
(1)@Configuration:把一个类作为一个IoC容器,他的某个方法头上如果注解了@Bean,那么就会作为bean存在spring容器中
以前我们写在配置文件,配置一个个bean,现在使用这个注解即可
图一创建的类使用了注解@Configuration,然后里面@Bean注解了一个方法
@Bean注解方法的返回值就作为实例存在ioc容器中了
图二中我们获取app然后获取实例即可
关于图一使用new 对象其实不是真的new出来的,是使用原型模式生成的,所以new几次都是同一实例
如下图
@Bean("person111")这里其实就是不使用方法名为实例名,而重新定义了一个
我们再次用方法名获取实例就会报错
改为person111又正常获取
总结下:优先取bean注解的value,其次是取方法名
(2)@ComponentScan
就跟之前xml 中的
如果你定义了包路径的话就扫描该路径下的所有组件,记住是组件,不是所有类,比如@Controller,@Service这种,或者@Component这种
可以看到person类有被扫描到
图一中@ComponentScan("com.robert.annotations.project")表示扫描该路径下所有组件加载到ioc容器中,正常来说该路径下的Person类不在此范围里,这里我们手动加了@Component注解,使其被扫描
但是,开发中,我们可能某些包的某些类不想扫描,这里我们就可以用过滤器excludeFilters 和 includeFilters
这里就不演示
@ComponentScan(value = "io.mieux",
excludeFilters = {@Filter(type = FilterType.ANNOTATION,
value = {Controller.class})})
意思就是我扫描io.mieux下的所有没有被@Controller注解的类
这里除了使用注解过滤,当你规则比较复杂的时候,还可以使用正则表达式啊,过滤类啊等待,
好了,第二个注解@ComponentScan我就说到这,总的来说就是扫描一些类,将这些类的实例放到IoC容器中,
然后我要用的时候不需要new,使用依赖注入即可
(3)@Scope
该注解用于指定作用域的,用在类上,这个注解也不复杂哦
现在我们把@Scope("prototype")注解注释
然后从容器中获取实例,可以看到是获取的相同的
现在解开注释
发现是不同的实例了
这里关于这个注解不多说
有四种场景:
不写时默认为单例
然后@Scope("prototype")代表每次获取实例创建新的
@Scope("request")表示在同一请求中,只创建一个实例
@Scope("session") 类似,表示在同一session中单例
第三个注解就到这
(4)@Lazy
延时加载,本来是在容器启动时就创建实例,使用该注解后,在调用该对象方法或者说用到该对象时才创建实例,延时加载是单例模式
上两图,先分别在实例创建与测试时容器创建的时候加上打印语句
可以看到是先将实例放入IoC,然后再打印初始化IOC容器
现在加上@Lazy注解
再看控制台,可以看到使用时才创建对象并加入IOC容器,怎么说呢,懒加载就像之前说的懒汉模式,用的时候我才创建,这样当你项目庞大时能提升不少性能
(5)@Conditional
意思是按照一定的条件判断是否给容器注册bean
使用@Conditional注解要配合Condition类,我们这里先定义俩Condition
然后测试,此demo实现操作系统为windows时创建james,为linux时创建tom
修改vm参数,模拟linux操作系统
此时测试创建tom实例
(6)@Import
这个作用就是导入外部资源,相当于手动指定第三方资源,把其实例加载到IoC中
配置类,还是配置了一个bean person
测试类,打印输出扫描到的类
测试类中使用@Import(value = {Cat.class})
发现打印的Ioc中的bean多了Cat类
还有一种方式,可以自定义ImportSelector
比如说我只想导入某几个类,或者我只想导入类名包含 "AP"的类
新建dog跟mouse类
自定义importSelector,import注解里的数组里加上
测试,可以看到,IoC中多了mouse跟dog类实例
继续,使用import注解还有第三种方式,这种更加体现了注解编程的灵活度
自定义MyImportBeanDefinitionRegistrator,里面逻辑是我如果Ioc注册列表里有Mouse跟Dog我就注册一个新的实例catt
测试发现成功注册catt
总结下,关于注册bean到IoC容器,有三种方式
1.@Bean 加一个注解一个
2.@ComponentScan可以注册某个包下的一堆组件
3.@Import 有三种方式(1.Xx.class,2.XximportSelector,3.XxImportBeanDefinitionRegistrator)
其实还有第四种
关于面试问的BeanFactory与FactoryBean区别:
其实FactoryBean就是spring内部的一个Bean,不过他的职责是负责将bean注册到IoC容器中,
而我们获取bean时使用FactoryBean即可获取
先整个MyFactoryBean,可以看到实现了三个方法,分别为返回对象,返回对象类型,是否单例
在配置类中多加一个Bean
可以看到返回的是MyFactoryBean对象,可以看到其实获取到的是monkey实例
也就是说,FactoryBean的作用就是注册实例,而我们设置的单例为true,也可以看到测试结果中俩对象相同
好了@Import注解到此结束
(7)bean的生命周期
配置阶段只剩最后一类注解了就是关于bean的生命周期
新建Car类
配置类
initMethod = "start",destroyMethod = "stop",表示初始化与销毁对象时分别调用对应的方法
测试下
然后是第二种
第二种是直接实现俩接口
重写destroy与afterPropertiesSet方法
配置文件改回去
Car类要加@Component注解
配置类加扫描组件的注解
再次运行测试方法
结果相同
现在说第三种
如图,使用注解@PostConstruct 与@PreDestroy
第四种方式
自定义MyBeanPostProcessor继承BeanPostProcessor接口
这种方式最灵活,这样写定义类,可以在其中获取所有bean,可以针对性的处理
测试正常
2.赋值组件(Injection Components)
这一部分的注解是日常开发中用的最多的,我先全部列举,你应该会有几个熟悉的
@Component,@Service,@Controller,@Repository,@Value,@Autowired,@PropertySource,@Qualifier,@Primary,@Resource,下面我一个个来讲解
@Component 泛指组件,当你的组件不好归类时,就用它进行标注
@Service,@Controller,@Repository都是@Component的子类,这四个注解都只是一个标注的作用,不过标注的对象不同
分别标注业务层,控制层,数据访问层
然后是@Value,这个注解就是起个赋值的作用
定义了一个类Bird,分别三种使用@Value的方式给属性赋值,分别是直接赋值,EL表达式,获取配置文件属性
使用配置文件属性时,记得在配置类上加上@PropertySource(value = "classpath:config.properties")
然后测试时可以看到获取对象的属性被成功赋值
刚刚这块就包含俩注解,@Value与@PropertySource
下面说下autowired,这个注解就是注入
使用autowired注解注入,
测试类中扫描这三个类的组件,其中编写service类时打印了dao的实例
说明我们注入DemoService类中的DemoDao的实例就是IoC中的
接下来是@Qualifier注解,当你不想要注入Ioc中的bean时,使用这个注解可以注入你指定的bean
这里我在DemoDao中整了个flag,值为1,正常注入DemoDao的话flag为1
我现在自定义bean,里面的flag为2
那么这个时候可以用Qualifier
测试可以看到我们注入的就是flag为2的自定义bean
把自定义里的flag改为4
使用@Resource注解
@Resource是针对所有的资源,比@Autowired与@Qualifier优先级更高
最后一个注解@Primary 优先 当俩bean名称相同时,其中一个加上@Primary注解,将获得优先权
3.织入组件(Weave Components)
@AppllicationContextAware:这是spring中的上下文环境对象,可以通过他得到IoC中的所有bean
还有一个是BeanDefinitionRegistryPostProcessor, 这个是用来注册额外的BeanDefinition的
BeanDefinition就是Bean配置的封装而已
4.切面组件(Aspect Components)
@Transactional 配置事务信息
@EnableTransactionManagement 添加事务管理,就是开启事务