学习来源:B站尚硅谷《Spring注解驱动开发》
内容较多,请结合CSDN网页右侧的目录组件阅读本文
文章未完结。如有错误欢迎批评指正,感谢!
J2EE
@Retention
@Target
@Documented
@Repeatable
@SuppressWarnings
Spring IoC
组件扫描
@ComponentScan
注解的value参数指明要扫描的包路径,比如value="cn.louzen",即cn.louzen路径下的所有注解了 @Component 及其子注解如 @Controller、@Service、@Repository、@Configuration等 的类都会被扫描并放入容器中
作用域:类
JDK8及以上,@ComponentScan 是可以重复放在同一个类上的,或者用@ComponentScans
@ComponentScan(basePackages={"cn.louzen"})
public class MainConfig {}
看它扫描到的所有组件:
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
String[] definitionNames = applicationContext.getBeanDefinitionNames();
for (String definitionName : definitionNames) {
System.out.println(definitionName);
}
可以在@ComponentScan中指定要扫描(includeFilters参数)或不扫描(excludeFilters参数)哪个包,
其中,type指明依据哪种类型过滤,classes指明要过滤的内容,
指定不扫描:
@ComponentScan(basePackages={"cn.louzen"}, excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})
})
public class MainConfig {}
指定要扫描:
@ComponentScan(basePackages={"cn.louzen"}, includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})
}, useDefaultFilters = false)
public class MainConfig {}
指定要扫描时要设置 useDefaultFilters = false,让默认过滤规则不生效
注解形式
<context:component-scan base-package="cn.louzen"></context:component-scan>
设置默认过滤规则不生效:use-default-filters="false"
@ComponentScan.@Filter
指定过滤规则
参数:
type:(过滤类型,取值是 org.springframework.context.annotation.FilterType 枚举类型)
ANNOTATION:按照注解过滤(常用)
ASSIGNABLE_TYPE:按照指定具体哪个类过滤(常用)
ASPECTJ:按照ASPECTJ表达式过滤
REGEX:按照正则表达式过滤
CUSTOM:自定义规则,规则类必须是org.springframework.core.type.filter.TypeFilter接口的实现类
classes:(对应type的值)
@ComponentScans
可以放多个 @ComponentScan
@ComponentScans(value = {
@ComponentScan(basePackages={"cn.louzen"})
})
组件注册
注册的方式有哪些
给容器中注册组件:(详情见下文对每个注解的解释)
1、包扫描 + 组件表注注解:(@ComponentScan扫描,@Component及其子注解注册组件)
2、@Bean:导入第三方包里的组件
3、@Import:快速给容器中导入一个组件,前提是组件的创建就是运行无参构造等简单的方式,不需要配置属性等操作
3.1、@Import({要注册进容器中的组件类.class}):容器中就会自动注册这个组件,id默认是组件类的全限定名(见下面@Import的内容)
3.2、@Import(ImportSelector实现类.class):ImportSelector接口,方法selectImports,方法返回需要导入的组件的全限定名的字符串数组(见下面@Import的内容)
3.3、@Import(ImportBeanDefinitionRegistrar实现类.class):BeanDefinition注册类,把所有需要添加到容器中的bean,可以调用 ImportBeanDefinitionRegistrar 的 registerBeanDefinition 方法手动注册进来(见下面@Import的内容)
4、使用Spring提供的FactoryBean(工厂Bean)接口,定义一个方法返回值是工厂类型,方法+@Bean可实现工厂的产品对象进容器
@Bean
被@Bean修饰的方法,参数中的对象类型是从Spring上下文中获取的
作用域:方法、注解
属性:
value(= name):bean名,xml配置中对应<bean>的id属性
name(= value):与value互为别名,一样的
initMethod:指定初始化方法
destroyMethod:指定销毁方法
对普通的方法,bean类型为方法返回值的类型,id默认是方法名(@Bean的参数可以指定id):
@Bean
public Person person() {
return new Person("lisi", 20);
}
获取对象:
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext(MainConfig.class);
Person person = applicationContext.getBean(Person.class);
同时,我们可以通过 applicationContext 上下文对象的一系列方法获取上下文的内容
比如获取一个类(type)在上下文中的所有bean name:
String[] beanNamesForType = applicationContext.getBeanNamesForType(Person.class);
for (String beanName : beanNamesForType) {
System.out.println(beanName);
}
对工厂方法,方法返回值虽然是工厂类型,但创建并放入容器的bean的类型为工厂方法的产品的类型,id默认还是方法名(可定义):
@Bean
public ColorFactoryBean colorFromFactory() {
return new ColorFactoryBean();
}
工厂类需要实现FactoryBean接口
ColorFactoryBean工厂类的定义见下面代码块“ ColorFactoryBean工厂类的定义 ”
注意:通过 applicationContext.getBean("工厂方法名,如colorFromFactory") 的方式默认获得的是产品类型的对象,想获取工厂类实例的话,就要在前面加&,如 getBean("&colorFromFactory")
ColorFactoryBean工厂类的定义
public class ColorFactoryBean implements FactoryBean<Color> {
// 返回一个Color对象,这个对象会添加进容器中
@Override
public Color getObject() throws Exception {
System.out.println("ColorFactoryBean...getObject...");
return new Color();
}
@Override
public Class<?> getObjectType() {
return Color.class;
}
// 控制是否单例,
// true:此bean单实例,在容器中保存一份;false:多实例,每次获取每次new,不保存进容器
@Override
public boolean isSingleton() {
return true;
}
}
Bean的生命周期
bean的生命周期:
bean的创建(construct) -> 初始化(初始化方法) -> 销毁(销毁方法)
容器管理bean的生命周期:
我们可以自定义初始化和销毁方法,容器在bean进行到当前生命周期的时候会调用我们自定义的这些方法
创建对象的时机:
单实例:容器启动的时候创建,可以设置为懒加载
多实例:用到的时候才创建
初始化:
对象创建完成,并赋值好,再调用初始化方法
销毁:
单实例:容器关闭的时候销毁
多实例:容器不会管理这个bean,容器不会调用销毁方法
方式一:
通过设置@Bean的initMethod、destroyMethod 指定初始化方法、指定销毁方法
用例见下面代码块“ @Bean设置initMethod、destroyMethod ”(singleton)
方式二:
通过让bean实现InitializingBean接口,实现方法afterPropertiesSet来定义初始化方法
通过让bean实现DisposableBean接口,实现方法destroy来定义销毁方法
用例见下面代码块“ 通过接口实现bean初始化销毁 ”
方式三:
通过注解实现
@PostConstruct:
在bean创建完成并且属性赋值完成后,执行初始化
作用域:方法(bean的初始化方法)
@PreDestroy:
在bean将要被从容器中移除之前,执行销毁
作用域:方法(bean的销毁方法)
用例见下面代码块“ 注解实现bean初始化销毁 ”
实现原理见下面代码块“ Spring底层使用BeanPostProcessor ”
方式四:
通过实现bean的后置处理器接口BeanPostProcessor实现,后置处理器作用是在bean初始化前后进行一些处理工作
org.springframework.beans.factory.config.BeanPostProcessor
接口方法:
postProcessBeforeInitialization(用于初始化前):
运行时机是在前三种bean的初始化方式运行之前(initMethod、afterPropertiesSet、@PostConstruct)
postProcessAfterInitialization(用于初始化后):
运行时机是在前三种bean的初始化方式运行之后(initMethod、afterPropertiesSet、@PostConstruct)
注意:BeanPostProcessor接口的实现类是单独的,不是bean类实现的,这不同于前面的实现方式
注意:BeanPostProcessor接口的两个方法都是针对初始化的,没有销毁的方法
注意:后置处理器的接口不用跟bean产生直接联系,后置处理器实现类创建并放入容器后会自动在bean的初始化过程中发挥作用
用例见下面代码块“ 后置处理器接口实现初始化 ”
几种方式的运行顺序:
见下面代码块“ 初始化注销方式执行顺序 ”
bean初始化过程源码:
见下面代码块“ bean初始化过程源码 ”
Spring底层对BeanPostProcessor的使用:
见下面代码块“ Spring底层使用BeanPostProcessor ”
@Bean设置initMethod、destroyMethod
// 实体类
public class Car {
public Car() {
System.out.println("car constructor");
}
public void init() {
System.out.println("car ... init .... ");
}
public void destroy() {
System.out.println("car ... destroy .... ");
}
}
// 组建注册
@Bean(initMethod = "init", destroyMethod = "destroy")
public Car car() {
return new Car();
}
// 测试用例
@Test
public void test01() {
// 这里会输出 car constructor
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
// 这里会输出 car ... init ....
System.out.println("容器创建完成");
applicationContext.close();
// 这里会输出 car ... destroy ....
}
通过接口实现bean初始化销毁
// 输出内容与 “ @Bean设置initMethod、destroyMethod ” 代码块中的一样
@Component
public class Cat implements InitializingBean, DisposableBean {
public Cat() {
System.out.println("cat constructor");
}
@Override
public void destroy() throws Exception {
System.out.println("cat...destroy...");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("cat...afterPropertiesSet...");
}
}
注解实现bean初始化销毁
// 输出内容与 “ @Bean设置initMethod、destroyMethod ” 代码块中的一样
@Component
public class Dog {
public Dog() {
System.out.println("Dog constructor");
}
// 对象创建并赋值之后调用
@PostConstruct
public