新手小白,有些时候使用注解的时候一知半解,特此将碰到过的注解功能、用法、原理做个笔记,长期更新。
1.注入Bean类注解,项目启动后扫描到这些注解会将这些注解作用域上的对象实例化并将信息存储到spring的map中(将bean信息放在位于beanFactory的beanDefinitionMap中)接口作用近似,但是一般规定不同的注解作用于不同含义的 类上。
作用域: ElementType.TYPE //接口、类、枚举、注解
ElementType.FIELD //字段、枚举的常量
ElementType.METHOD//方法
ElementType.PARAMETER //方法参数
ElementType.CONSTRUCTOR //构造函数
ElementType.LOCAL_VARIABLE//局部变量
ElementType.ANNOTATION_TYPE//注解
ElementType.PACKAGE ///包
注解名 | 作用域 | 功能 | 使用场景 | 详细说明 |
@Controller | ElementType.TYPE | 略 | 略 | |
@Service | ElementType.TYPE | 略 | 略 | |
@repository | ElementType.TYPE | 略 | 略 | |
@Component | ElementType.TYPE | 略 | 略 | |
@Configuration | ElementType.TYPE | 略 | 一般用于自己的配置类 | 也只是通知spring将自己 实例化 |
@Bean | ElementType.METHOD,ElementType.ANNOTATION_TYPE | 略 | 可作用于方法上,对象是方法返回值 |
spring实例化bean的过程
第一步:调用Bean的默认构造方法(也可以是指定的其它构造方法),生成bean实例。
第二步:检查Bean配置文件中是否注入了Bean的属性值,如果有注入,则在bean1实例的基础上对其属性进行注入,把原来的bean1给覆盖掉形成新的bean实例:bean2。
第三步:检查Bean是否实现了InitializingBean接口,如果实现了此接口,则调用afterPropertiesSet()方法对bean2进行相应操作后,把bean2覆盖形成新的bean实例:bean3。
第四步:检查Bean配置文件中是否指定了init-method此属性,如果已指定,则调用此属性对应方法并对bean3进行相应操作后,最终把bean3覆盖形成新的实例:bean4。
protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd) throws Throwable {
//判断该bean是否实现了实现了InitializingBean接口,如果实现了InitializingBean接口,则只掉调用bean的afterPropertiesSet方法
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
if (logger.isDebugEnabled()) {
logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
}
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
public Object run() throws Exception {
//直接调用afterPropertiesSet
((InitializingBean) bean).afterPropertiesSet();
return null;
}
},getAccessControlContext());
} catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
//直接调用afterPropertiesSet
((InitializingBean) bean).afterPropertiesSet();
}
}
if (mbd != null) {
String initMethodName = mbd.getInitMethodName();
//判断是否指定了init-method方法,如果指定了init-method方法,则再调用制定的init-method
if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
//进一步查看该方法的源码,可以发现init-method方法中指定的方法是通过反射实现
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}