注解:
注解 |
释义 |
@Configuration |
告诉Spring这是一个配置类 |
@Bean |
注册一个Bean,类型是返回值类型,默认方法名作为ID |
@Component |
告诉容器这是个组件(泛指各种组件) |
@ComponentScan |
包扫描(为了实例化对象) |
@Filter |
过滤@ComponentScan中不想扫描的组件[1.1]
|
@Repository |
标注数据访问组件,即DAO组件 |
@Service |
标注业务层组件 |
@Controller |
用于标注控制层组件(如struts中的action) |
@Scope |
实例化的模式[1.2]
|
@Lazy |
容器启动不创建对象,第一次使用时创建 |
@Conditional |
按照一定条件判断满足条件给容器中注册bean[1.3]
|
@Import |
快速给容器中导入一个组件[1.4]
|
@PostConstruct |
标注这个方法为初始化方法,对象创建并赋值后调用[3.3]
|
@PreDestroy |
标注这个方法为销毁方法,容器移除对象之前调用[3.3]
|
组件注册:
- 包扫描+组件标注注解 (@Controller/@Service/@Repository/@Component) [自己写的类]
- @Bean (例如:实例化一个对象返回) [导入的第三方包的组件]
- @Impoer [快速给容器中导入一个组件]
- 使用Spring提供的FactoryBean(工厂Bean)[2.1]
生命周期:
- 通过@Bean注解指定初始化和销毁方法:指定init-method和destory-method[3.1]
- 通过让bean实现InitializingBean接口定义初始化逻辑,实现DisposableBean接口定义销毁逻辑[3.2]
- 可以使用JSR-250里的@PostConstruct和@PreDestroy注解标注初始化和销毁方法[3.3]
- BeanPostProcessor:bean的后置处理器,在bean初始化前后进行一些处理工作,以及其他应用[3.4]
构造(对象创建)
- 单实例:在容器创建时创建对象
- 多实例:在每次获取时创建对象
初始化前调用:
- BeanPostProcessor.postProcessBeforeInitialization
初始化:
初始化后调用:
- BeanPostProcessor.postProcessAfterInitialization
销毁:
- 单实例:容器关闭时销毁
- 多实例:容器管理这个bean,容器不会调用销毁方法
脚注:
[1.1]
// 在配置类前加@ComponentScan
// 参数一:value:指定扫描的包
// 参数二:excludeFilters/includeFilters = Filter[],扫描的时按照规则排除哪些组件/扫描时只需要包含哪些组件
// 参数三:useDefaultFilters,默认扫描规则扫描所有,使用includeFilters时要禁用默认规则
// @Filter
// FilterType.ANNOTATION(),按照注解
// FilterType.ASSIGNABLE_TYPE, 按照给定的类型
// FilterType.ASPECTJ,使用ASPECTJ表达式
// FilterType.REGEX,使用正则表达式
// FilterType.CUSTOM,使用自定义规则
@ComponentScan(value = "edu.wong", includeFilters = {
@Filter(type = FilterType.ANNOTATION, classes = { Controller.class }),
@Filter(type = FilterType.ASSIGNABLE_TYPE, classes = { BookService.class }),
@Filter(type = FilterType.CUSTOM, classes = { MyTypeFilter.class }) }, useDefaultFilters = false)
// 自定义扫描规则实例(必须实现TypeFilter)
public class MyTypeFilter implements TypeFilter {
/**
* metadataReader:读取到的当前正在扫描的类的信息
* metadataReaderFactory:可以获取到其他任何类的信息
*/
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
throws IOException {
// 获取当前类的注解信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
// 获取当前正在扫描的类的信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
// 获取当前资源(类的路径)
Resource resource = metadataReader.getResource();
// 获取正在扫描的类名
String className = classMetadata.getClassName();
// 包含er的可以被获取
if (className.contains("er")) {
return true;
}
return false;
}
}
[1.2]
@Configuration
public class MainConfig {
/**
* @Scope
* singleton:单例模式(默认值),全局有且仅有一个实例,ioc容器启动时会调用方法创建对象放到ioc容器中,以后每次直接从容器中获取
* prototype:原型模式,ioc容器启动时不会调用方法创建对象,每次获取Bean的时候会有一个新的实例
* request:每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效
* session:每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP session内有效
*
* @Lazy
* 懒加载:单例模式下起作用,默认在容器启动时创建对象,容器启动不创建对象.第一次使用使用(获取)Bean创建对象
*/
@Lazy
@Scope("singleton")
@Bean("person")
public Person person() {
return new Person("王五", 20);
}
}
[1.3]
// 标记在类上
// 满足条件,类中的配置的所有bean注册才会生效
@Conditional({ WindownsCondition.class })
@Configuration
public class MainConfig {
@Lazy
@Bean("person")
public Person person() {
return new Person("王五", 20);
}
// 标记在方法上
// 使用Conditiona,满足条件,bean注册才会生效
@Conditional({ WindownsCondition.class })
@Bean("win")
public Person person01() {
return new Person("win", 21);
}
@Conditional({ LinuxCondition.class })
@Bean("linux")
public Person person02() {
return new Person("Linux", 22);
}
}
// 实现Condition接口
public class LinuxCondition implements Condition {
/**
* ConditionContext:判断条件能使用的上下文(环境)
* AnnotatedTypeMetadata:注释信息
*/
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 获取到ioc使用的beanfactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// 获取类加载器
ClassLoader classLoader = context.getClassLoader();
// 获取当前环境信息
Environment environment = context.getEnvironment();
// 获取到bean定义的注册类
BeanDefinitionRegistry registry = context.getRegistry();
// 判断容器中注册情况,也可以在容器中注册bean
boolean containsBeanDefinition = registry.containsBeanDefinition("person");
String property = environment.getProperty("os.name");
if (property.contains("Linux")) {
return true;
}
return false;
}
}
[1.4]
@Configuration
// 在配置文件上直接用 @Import(要导入的组件),id默认是组件的全类名
// 1. 导入单个,导入多个用数组形式
// 2. 可以自定义导入组需要实现件ImportSelector接口后在@import注解中添加
// 3. 可以实现ImportBeanDefinitionRegistrar接口手动注册bean,之后在@import注解中添加
// 如下:
@Import(Color.class)
@Import( {Blue.class, Red.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class} )
public class MainConfig {
// TODO
}
// 自定义逻辑返回需要导入的组件
public class MyImportSelector implements ImportSelector {
// 返回值:要导入组件的全类名
// AnnotationMetadata当前标注@Import类的所有注解信息
// 方法返回 null 会报空指针异常
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[] { "edu.wong.bean.Blue", "edu.wong.bean.Yellow" };
}
}
// 自定义通过registerBeanDefinition()方法注册bean
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
/**
* AnnotationMetadata 当前类的注解信息
* BeanDefinitionRegistry BeanDefinitio注册类
* 把所有需要添加到容器中的bean:调用BeanDefinitionRegistry.registerBeanDefinition手动注册进来
*/
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 测试条件如果两种颜色存在就注册TwoColor类
boolean blue = registry.containsBeanDefinition("edu.wong.bean.Blue");
boolean yellow = registry.containsBeanDefinition("edu.wong.bean.Yellow");
if (blue && yellow) {
// 把TwoColor转换成Bean的定义信息(可以被参数二接收的参数)
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(TwoColor.class);
// 参数一:指定bean名
// 参数二:指定bean的定义信息
registry.registerBeanDefinition("twoColor", rootBeanDefinition);
}
}
}
[2.1]
//创建一个Spring定义的工场Bean
// FactoryBean<T> T:指定要创建对象的类型
public class MyFactoryBean implements FactoryBean<Color> {
// 返回一个Color对象这个对象会添加到容器中
public Color getObject() throws Exception {
System.out.println("MyFactoryBean......getObject.......");
return new Color();
}
// 返回对象的类型
// 默认获取的是工厂bean调用getObject创建的对象
// 要获取工程bean本身需要在id前加上 & 符号
public Class<?> getObjectType() {
return Color.class;
}
// 是否是单实例
// true这个Bean在容器中保存一份
// false每次获取都会创建一个新的
public boolean isSingleton() {
return true;
}
}
// 在配置类里使用@Import()把MyFactoryBean导入到容器
@Import(MyFactoryBean.class)
// 用全类名获取到Bean
// 打印测试
// 结果:--------->class edu.wong.bean.Color是MyFactoryBean里new的Color
/**
* 在getBean()加'&'如"&edu.wong.bean.MyFactoryBean";可以获取到MyFactoryBean本身,而不是返回值的Bean
*/
Object bean = annotationConfigApplicationContext.getBean("edu.wong.bean.MyFactoryBean");
System.out.println("--------->" + bean.getClass());
[3.1]
public class Car {
public Car() {
System.out.println("car constructor...");
}
public void init() {
System.out.println("car...init...");
}
public void destory() {
System.out.println("car...destory...");
}
}
/**
* bean的生命周期:创建-->初始化-->销毁
* 容器管理bean的生命周期:可以自定义初始化和销毁方法,容器bean进行到当前生命周期的时候会调用我们自定义的初始化和销毁方法
*
*/
@Configuration
public class MainConfigLifeCycle {
// initMethod指定bean的初始化方法
// destroyMethod指定bean的销毁方法
@Bean(initMethod = "init", destroyMethod = "destory")
public Car car() {
return new Car();
}
}
// 结果打印:
// car constructor...
// car...init...
// car...destory...
public class IocTestLiftCycle {
@Test
public void test() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfigLifeCycle.class);
context.close();
}
}
[3.2]
// 告诉容器这是个组件
// 实现InitializingBean, DisposableBean两个接口
@Component
public class Car implements InitializingBean, DisposableBean {
public Car() {
System.out.println("car constructor...");
}
public void destroy() throws Exception {
System.out.println("car destroy...");
}
public void afterPropertiesSet() throws Exception {
System.out.println("car afterPropertiesSet...");
}
}
// 扫描edu.wong.bean下的组件
@ComponentScan("edu.wong.bean")
@Configuration
public class MainConfigLifeCycle {
}
// 结果打印:
// car constructor...
// car afterPropertiesSet...
// car destroy...
public class IocTestLiftCycle {
@Test
public void test() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfigLifeCycle.class);
context.close();
}
}
[3.3]
<!-- 找不到这两个注解请在pom.xml下面的添加库 -->
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
@Component
public class Car {
public Car() {
System.out.println("car constructor......");
}
// 标注这个方法为初始化方法,对象创建并赋值后调用
@PostConstruct
public void init() {
System.out.println("car init......");
}
// 标注这个方法为销毁方法,容器移除对象之前调用
@PreDestroy
public void destroy() {
System.out.println("car destroy......");
}
}
[3.4]
/**
* @Component:把这个组件加入到容器中
* 会在所有bean初始化之前调用postProcessBeforeInitialization
* 会在所有bean初始化之后调用postProcessAfterInitialization
*
* 参数一(bean):容器创建好的实例
* 参数二(beanName):这个实例在容器中的名字
*/
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("--->postProcessBeforeInitialization---" + beanName + "===>" + bean);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("--->postProcessAfterInitialization---" + beanName + "===>" + bean);
return bean;
}
}
// BeanPostProcessor原理:
// postProcessBeforeInitialization函数的调用链如下:
-->refresh()
-->finishBeanFactoryInitialization(beanFactory)
-->beanFactory.preInstantiateSingletons();
-->getBean(beanName)
-->doGetBean(name, null, null, false);
-->getSingleton(String beanName, ObjectFactory<?> singletonFactory)
-->singletonFactory.getObject()
-->AbstractBeanFactory.this.createBean(beanName, mbd, args)
-->doCreateBean(beanName, mbdToUse, args)
-->initializeBean(beanName, exposedObject, mbd)
// 1.在initializeBean()执行之前,首先执行的是populateBean()函数,该函数主要是为Bean的各个属性赋值。
try {
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
// 2.在initializeBean(beanName, exposedObject, mbd) 中观察调用的代码
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
// 3.查看applyBeanPostProcessorsBeforeInitialization和applyBeanPostProcessorsAfterInitialization函数代码
// 获取容器中的所有BeanPostProcessors,循环调用postProcessBeforeInitialization方法(MyBeanPostProcessor里的方法)
// 一但返回null,跳出for循环,不会执行后面的BeanPostProcessor.postProcessorsBeforeInitialization
// 对于容器中每一个Bean实例,只要符合if语句条件,都会执行这两个函数,并不是实现BeanPostProcessor接口才会进入这两个函数。
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
/**
* BeanPostProcessor流程:
* populateBean(beanName, mbd, instanceWrapper);
* initializeBean{
* applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
* invokeInitMethods(beanName, wrappedBean, mbd);执行自定义初始化
* applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
* }
*/
// ApplicationContextAware示例
@Component
public class Car implements ApplicationContextAware {
// 把获取到的ioc容器里的内容保存下来
ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;=
}
}
// Spring底层对BeanPostProcessor的使用:bean赋值,注入其他组件,@AutoWired,生命周期注解,AsyncAnnotationBeanPostProcessor,......
// ApplicationContextAwareProcessor:实现容器中bean在初始化时,需要得到Spring容器内容
// BeanValidationPostProcessor:一般用于Web数据校验
网友评论