加载类

实例化前 -----》InstantiationAwareBeanPostProcessor

实例化

mergedBeanDefinitionBeanPostProcessor.applyMergedBeanDefinitionPostProcessors

找注入点

实例化后 --》 InstantiationAwareBeanPostProcessor 程序员手动填充属性

填充属性、 byType、byName

填充属性后 --》 InstantiationAwareBeanPostProcessors 中的 postProcessPropertyValues 、postProcessProperties 进行依赖注入

Aware

初始化前 -- BeanPostProcessor

初始化

初始化后 -- BeanPostProcessor

spring依赖注入的方式:

1、手动注入 依赖的是set方法

依赖 set方法底层原理

依赖 构造函数方法底层原理

2、 自动注入

1、xml的自动注入 什么是xml的自动注入

1、set方法 2、构造方法

依赖 set方法底层原理

依赖 构造函数方法底层原理

判断什么方法是set 方法 : 1、方法名以set开头 2、入参只有一个

这边判断set方法的代码在哪里呢?利用Java内省里面的代码设置的

AbstractAutowireCapableBeanFactory#autowireByType

AbstractAutowireCapableBeanFactory#unsatisfiedNonSimpleProperties

这个调用链很深一直到Introspector#getTargetPropertyInfo

下面为代码片段:

private PropertyDescriptor[] getTargetPropertyInfo() {

    // Check if the bean has its own BeanInfo that will provide
// explicit information.
PropertyDescriptor[] explicitProperties = null;
if (explicitBeanInfo != null) {
explicitProperties = getPropertyDescriptors(this.explicitBeanInfo);
}

if (explicitProperties == null && superBeanInfo != null) {
// We have no explicit BeanInfo properties. Check with our parent.
addPropertyDescriptors(getPropertyDescriptors(this.superBeanInfo));
}

for (int i = 0; i < additionalBeanInfo.length; i++) {
addPropertyDescriptors(additionalBeanInfo[i].getPropertyDescriptors());
}

if (explicitProperties != null) {
// Add the explicit BeanInfo data to our results.
addPropertyDescriptors(explicitProperties);

} else {

// Apply some reflection to the current class.

// First get an array of all the public methods at this level
Method methodList[] = getPublicDeclaredMethods(beanClass);

// Now analyze each method.
for (int i = 0; i < methodList.length; i++) {
Method method = methodList[i];
if (method == null) {
continue;
}
// skip static methods.
int mods = method.getModifiers();
if (Modifier.isStatic(mods)) {
continue;
}
String name = method.getName();
Class<?>[] argTypes = method.getParameterTypes();
Class<?> resultType = method.getReturnType();
int argCount = argTypes.length;
PropertyDescriptor pd = null;

if (name.length() <= 3 && !name.startsWith(IS_PREFIX)) {
// Optimization. Don't bother with invalid propertyNames.
continue;
}

try {

if (argCount == 0) {
if (name.startsWith(GET_PREFIX)) {
// Simple getter
pd = new PropertyDescriptor(this.beanClass, name.substring(3), method, null);
} else if (resultType == boolean.class && name.startsWith(IS_PREFIX)) {
// Boolean getter
pd = new PropertyDescriptor(this.beanClass, name.substring(2), method, null);
}
} else if (argCount == 1) {
if (int.class.equals(argTypes[0]) && name.startsWith(GET_PREFIX)) {
pd = new IndexedPropertyDescriptor(this.beanClass, name.substring(3), null, null, method, null);
} else if (void.class.equals(resultType) && name.startsWith(SET_PREFIX)) {
// Simple setter
pd = new PropertyDescriptor(this.beanClass, name.substring(3), null, method);
if (throwsException(method, PropertyVetoException.class)) {
pd.setConstrained(true);
}
}
} else if (argCount == 2) {
if (void.class.equals(resultType) && int.class.equals(argTypes[0]) && name.startsWith(SET_PREFIX)) {
pd = new IndexedPropertyDescriptor(this.beanClass, name.substring(3), null, null, null, method);
if (throwsException(method, PropertyVetoException.class)) {
pd.setConstrained(true);
}
}
}
} catch (IntrospectionException ex) {
// This happens if a PropertyDescriptor or IndexedPropertyDescriptor
// constructor fins that the method violates details of the deisgn
// pattern, e.g. by having an empty name, or a getter returning
// void , or whatever.
pd = null;
}

if (pd != null) {
// If this class or one of its base classes is a PropertyChange
// source, then we assume that any properties we discover are "bound".
if (propertyChangeSource) {
pd.setBound(true);
}
addPropertyDescriptor(pd);
}
}
}
processPropertyDescriptors();

// Allocate and populate the result array.
PropertyDescriptor result[] =
properties.values().toArray(new PropertyDescriptor[properties.size()]);

// Set the default index.
if (defaultPropertyName != null) {
for (int i = 0; i < result.length; i++) {
if (defaultPropertyName.equals(result[i].getName())) {
defaultPropertyIndex = i;
}
}
}

return result;
}


2、@Autowire 自动注入

希望spring不去调用set方法

  @Bean 替代<Bean></Bean>
1、set方法
2、 属性
3、 构造方法
此时就不需要提供属性的set方法
先byType 再Byname ---> 先属性的类型 ,再属性的名字


3、xml 的byType byName是spring自带的,

但是@Autowire 是通过BeanPostProcess 实现的,是spring的插件机制

4、value注解的使用

5、查找bean的候选者

DefaultListableBeanFactory#findAutowireCandidates

DefaultListableBeanFactory#isAutowireCandidate

6、为啥xml配置的自动注入 byType 获取多个bean之后只能报错?

为什么因为byType 封装的AutowireByTypeDependencyDescriptor.getDependencyName()==null

而@Autowire 是先ByType 再ByName

6、一个对象实例化后从spring容器取出放在bean对象中,

写出获取它的属性的set方法 ​​javascript:void(0)​

思路:可以用java的内省获取bean的属性描述器ps(bean的全部属性),若其中属性pd(ps中的一个)和从配置文件解析出的bean的某个属性相等,则Method method=pd.getWriteMethod( ),那么这个method就是那个属性的set方法

appl

PropertyDescriptor[] ps = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();

for(PropDef propDef : beanDef.getPropertys()){ //beanDef是我们昨天设计出用来存放解析bean的list

   for(PropertyDescriptor pd : ps){

  if(propDef.getName().equals(pd.getName())){//PropDef是我们昨天设计出用来存放bean下面的property的 list

   Method setter = pd.getWriteMethod();//获取属性的setter方法 ,p

   Object value = map.get(proDef.getRef());

   setter.invoke(bean, value);//把引用对象注入到属性

8、xml 默认是关闭autowire注解

想要使用@Autowire 有两种方式: 1、切换容器到AnnotationConfigApplicationContext

2、 spring.xml 注解中开启新增context:annotation-config/

现在开始讲@Autowire

9、Spring IoC 依赖注入(三)resolveDependency ​​javascript:void(0)​

认知一下,与依赖查找的相关 API:

resolveDependency:支持 Optional、延迟注入、懒加载注入、正常注入。

Spring依赖注入之注入Bean获取详解:​​javascript:void(0)​

doResolveDependency:在依赖查找之前,想办法快速查找,

如缓存 beanName、@Value 等直接获取注入的值,避免通过类型查找,

最后才对集合依赖和单一依赖分别进行了处理。

实际上,无论是集合依赖还是单一依赖查找都是调用 findAutowireCandidates 方法。

findAutowireCandidates:真正在 Spring IoC 容器中进行依赖查找,

依赖查找的来源有三:①内部对象 ②托管Bean ③BeanDefinition。

最后如果无法查找到依赖对象,会进行一些补偿机制,想方设法获取注入的对象,如泛型补偿,自引用补偿。

isAutowireCandidate:判断候选对象是否可用,

有三重过滤规则:①bd.autowireCandidate=true -> ②泛型匹配 -> ③@Qualifier。委托给 ContextAnnotationAutowireCandidateResolver。

泛型匹配的demo:

​javascript:void(0)​​ Spring泛型依赖注入

​https://www.zhihu.com/question/268195272​​ spring4的泛型依赖注入是什么原理?

其中函数 isAutowireCandidate 往里面找public boolean isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor) {

if (!super.isAutowireCandidate(bdHolder, descriptor)) {

// If explicitly false, do not proceed with any other checks...

return false;

}

return checkGenericTypeMatch(bdHolder, descriptor);

}看到这里有范型检查相关的内容,再往深入找,会看到这段代码if (checkGenerics) {

// Recursively check each generic

ResolvableType[] ourGenerics = getGenerics();

ResolvableType[] typeGenerics = other.as(ourResolved).getGenerics();

if (ourGenerics.length != typeGenerics.length) {

return false;

}

if (matchedBefore == null) {

matchedBefore = new IdentityHashMap<>(1);

}

matchedBefore.put(this.type, other.type);

for (int i = 0; i < ourGenerics.length; i++) {

if (!ourGenerics[i].isAssignableFrom(typeGenerics[i], matchedBefore)) {

return false;

}

}

}所以 spring 其实是利用反射机制,获取类型的范型的,然后做了比较返回了合适的 bean 进行注入的。

Spring 注解原理(三)AutowireCandidateResolver:@Qualifier @Value @Autowire @Lazy

​http://t.zoukankan.com/binarylei-p-10428999.html#4-generictypeawareautowirecandidateresolver​

8、自己注入自己就是类似下面

1、 A a = new A();

a.a =a;

9、

UserService.java

@Component

public class UserService {

@Autowired

public OrderService orderService;

public void test(){
System.out.println(this.orderService);
}


}

OrderService.java

@Component

@Scope("prototype")

public class OrderService {

}

Test.java

public class Test {

public static void main(String[] args) {

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

UserService userService = (UserService) applicationContext.getBean("userService");

userService.test();

userService.test();

userService.test();

}

}

com.luban.service.OrderService@2f7298b

com.luban.service.OrderService@2f7298b

com.luban.service.OrderService@2f7298b

当UserService注入的类型是ObjectFactory的时候可以改变成其他结果

@Component

public class UserService {

@Autowired

public ObjectFactory orderService;

public void test(){
System.out.println(this.orderService.getObject());
}


}

com.luban.service.OrderService@4cc451f2

com.luban.service.OrderService@294425a7

com.luban.service.OrderService@9f116cc

  1. 当注入的属性带有@Lazy注解,则会注入代理类。只有代理类调用方法的时候才会注入bean (才会执行doResolveDependency方法)
    @Rsource
    对于@Resource:
  2. 如果@Resource注解中指定了name属性,那么则只会根据name属性的值去找bean,如果找不到则报错
  3. 如果@Resource注解没有指定name属性,那么会先判断当前注入点名字(属性名字或方法参数名字)是不是存在Bean,如果存在,则直接根据注入点名字取获取bean,如果不存在,则会走@Autowired注解的逻辑,会根据注入点类型去找Bean
    3、如果

@Resource 不能注入静态的属性或者方法会抛异常

@Autowire 不能成功注入静态的属性或者方法,会打印日志

除了 value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);这行代码,其他在上一篇笔记中已经写了;总结下这个过程就是:

1.根据注入类型判断如果是ObjectFactory,返回一个ObjectFactory对象,程序员通过ObjectFactory.getObject来获取对象,如果是原型对象,那么每次获取的对象都不一样;也就是说通过一个原型bean对象,通过注入过后,每次执行getObject都是不一样的对象。

2.如果是Optional对象,然后获取一个Bean对象,封装成Optional对象返回;

3.如果是一般的注入对象,那么过程如下:

如果有@Value注解,处理@Value注解;

否则处理Map、Collection、Array类型的注入,如果是这些类型,那么会从容器获取bean然后封装成Map or Collection or Array类型,然后返回;

最后调用findAutowireCandidates方法得到根据注入类型找到的所有bean

a.isAutowireCandidate的验证(默认为true)

b.泛型的验证;

c.Qualifier的筛选;

通过这些验证过后得到了一个Map集合,Map集合就是符合条件的所有bean,如果这个Map只有一条数据那么直接简单处理返回,如果这个Map大于1的时候,就要进行进一步的唯一筛选,筛选过程如下:

找到有多个bean,这里的处理就比较麻烦一点了

determineAutowireCandidate确定唯一Bean的三步操作

1.检查是否有@Primary注解,如果有就取配置了@Primary注解的bean,如果发现有不止一个bean有@Primary,则报错;如果没有这注解,当没调用

@primary作用在bean定义上面

当从容器中查找一个bean的时候,如果容器中出现多个Bean候选者时,可以通过primary="true"将当前bean置为首选者,那么查找的时候就会返回主要的候选者,否则将抛出异常。

2.检查是否有@Priority注解,如果有判断优先级,如果有两个bean的优先级相同则报错;如果没有这注解,当没调用

@Priority 注解作用在类上面,被@Priority注解的类,其值越小,在单值注入时,越优先选择。

3.如果前两步还没有确定唯一的bean,那么最后一步就是byName,找到唯一的bean。

所以找bean的过程是:

byType->Map等集合处理->自动注入候选者验证->Qualifier的筛选->@Primary->@Priority->byName的过程

所以依赖注入不仅仅是先byType,再byName,这中间还有很多过程。

Spring依赖注入之注入Bean获取详解 ​​javascript:void(0)​

从源码分析@Qualifier,@Primary,@Priority的候选顺序

@Primary、@Priority、@Qualifier的用法??​

自己注入自己

定义一个类,类里面提供了一个构造方法,用来设置name属性

public class UserService {

private String name;

public UserService(String name) {

this.name = name;

}

public String getName() {

return name;

}

@Autowired

private UserService userService;

public void test() {

System.out.println(userService.getName());

}

}

然后针对UserService定义两个Bean:

@Bean

public UserService userService1() {

return new UserService("userService1");

}

@Bean

public UserService userService() {

return new UserService("userService");

}

按照正常逻辑来说,对于注入点:

@Autowired

private UserService userService;

会先根据UserService类型去找Bean,找到两个,然后根据属性名字“userService”找到一个beanName为userService的Bean,但是我们直接运行Spring,会发现注入的是“userService1”的那个Bean。

这是因为Spring中进行了控制,尽量“自己不注入自己”。

涉及到的代码:

findAutowireCandidates

// 对候选bean进行过滤,首先候选者不是自己,然后候选者是支持自动注入给其他bean的

for (String candidate : candidateNames) { // beanName orderSer1 order2 oser

// isAutowireCandidate方法中会去判断候选者是否和descriptor匹配

if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {

addCandidateEntry(result, candidate, descriptor, requiredType);

}

}

// 3. 补偿机制:如果依赖查找无法匹配,怎么办?包含泛型补偿和自身引用补偿两种。

if (result.isEmpty()) {

boolean multiple = indicatesMultipleBeans(requiredType);

// 3.1 fallbackDescriptor: 泛型补偿,实际上是允许注入对象类型的泛型存在无法解析的情况

DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();

// 3.2 补偿1:不允许自称依赖,但如果是集合依赖,需要过滤非@Qualifier对象。什么场景?

for (String candidate : candidateNames) {

if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor) &&

(!multiple || getAutowireCandidateResolver().hasQualifier(descriptor))) {

addCandidateEntry(result, candidate, descriptor, requiredType);

}

}

// 3.3 补偿2:允许自称依赖,但如果是集合依赖,注入的集合依赖中需要过滤自己

if (result.isEmpty() && !multiple) {

for (String candidate : candidateNames) {

if (isSelfReference(beanName, candidate) &&

(!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate)) &&

isAutowireCandidate(candidate, fallbackDescriptor)) {

addCandidateEntry(result, candidate, descriptor, requiredType);

}

}

}

}

spring的销毁:

Bean的销毁过程

  1. 容器关闭
  2. 发布ContextClosedEvent事件
  3. 调用LifecycleProcessor的onClose方法
  4. 销毁单例Bean
  5. 找出所有DisposableBean(实现了DisposableBean接口的Bean)
  6. 遍历每个DisposableBean
  7. 找出依赖了当前DisposableBean的其他Bean,将这些Bean从单例池中移除掉
  8. 调用DisposableBean的destroy()方法
  9. 找到当前DisposableBean所包含的inner beans,将这些Bean从单例池中移除掉 (inner bean参考https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-inner-beans)
    这里涉及到一个设计模式:适配器模式
    在销毁时,Spring会找出实现了DisposableBean接口的Bean。

Spring依赖注入之@Resourcce详解&Bean的销毁:

​javascript:void(0)​

Bean的销毁

当容器进行关闭的时候需要对bean和bean工厂以及一系列的容器进行销毁,

这个时候销毁只是对容器的bean对象进行销毁,不意味着对对象进行销毁;销毁分为两种,

手动销毁和自动销毁,手动销毁需要调用容器的close方法进行销毁,

而自动销毁是向jvm注册一个钩子线程,

当容器进行关闭的时候会自动调用销毁的钩子线程进行销毁,

比如我们的jvm关闭的时候会自动来调用你的钩子线程来销毁容器的bean

// Publish shutdown event.向spring容器发布一个事件,表示容器即将关闭

publishEvent(new ContextClosedEvent(this));

spring容器的关闭不代表jvm的关闭,如果定义了事件关闭监听器的话 jvm可以收到事件关闭的监听器

dubbo里面会监听到关闭事件

public DisposableBeanAdapter(Object bean, String beanName, RootBeanDefinition beanDefinition,
List<BeanPostProcessor> postProcessors, @Nullable AccessControlContext acc) {

Assert.notNull(bean, "Disposable bean must not be null");
//销毁方法所在的bean对象
this.bean = bean;
this.beanName = beanName;
//这个属性invokeDisposableBean是表示你的销毁方法 实现了DisposableBean并且bean中不存在destroy方法
this.invokeDisposableBean =
(this.bean instanceof DisposableBean && !beanDefinition.isExternallyManagedDestroyMethod("destroy"));
//是否允许非public的构造或者普通方法执行
this.nonPublicAccessAllowed = beanDefinition.isNonPublicAccessAllowed();
this.acc = acc;
// javascript:void(0)
String destroyMethodName = inferDestroyMethodIfNecessary(bean, beanDefinition);
// 当前bean没有实现DisposableBean 并且 !"destroy".equals(destroyMethodName)
// bean中不存在destroyMethodName方法
// destroyMethodName 不为空
if (destroyMethodName != null && !(this.invokeDisposableBean && "destroy".equals(destroyMethodName)) &&
!beanDefinition.isExternallyManagedDestroyMethod(destroyMethodName)) {
this.destroyMethodName = destroyMethodName;
Method destroyMethod = determineDestroyMethod(destroyMethodName);
if (destroyMethod == null) {
if (beanDefinition.isEnforceDestroyMethod()) {
throw new BeanDefinitionValidationException("Could not find a destroy method named '" +
destroyMethodName + "' on bean with name '" + beanName + "'");
}
}
else {
Class<?>[] paramTypes = destroyMethod.getParameterTypes();
if (paramTypes.length > 1) {
throw new BeanDefinitionValidationException("Method '" + destroyMethodName + "' of bean '" +
beanName + "' has more than one parameter - not supported as destroy method");
}
else if (paramTypes.length == 1 && boolean.class != paramTypes[0]) {
throw new BeanDefinitionValidationException("Method '" + destroyMethodName + "' of bean '" +
beanName + "' has a non-boolean parameter - not supported as destroy method");
}
destroyMethod = ClassUtils.getInterfaceMethodIfPossible(destroyMethod);
}
this.destroyMethod = destroyMethod;
}
this.beanPostProcessors = filterPostProcessors(postProcessors, bean);
}
private String inferDestroyMethodIfNecessary(Object bean, RootBeanDefinition beanDefinition) {
String destroyMethodName = beanDefinition.getDestroyMethodName();
if (AbstractBeanDefinition.INFER_METHOD.equals(destroyMethodName) ||
(destroyMethodName == null && bean instanceof AutoCloseable)) {
// Only perform destroy method inference or Closeable detection
// in case of the bean not explicitly implementing DisposableBean
if (!(bean instanceof DisposableBean)) {
try {
return bean.getClass().getMethod(CLOSE_METHOD_NAME).getName();
}
catch (NoSuchMethodException ex) {
try {
return bean.getClass().getMethod(SHUTDOWN_METHOD_NAME).getName();
}
catch (NoSuchMethodException ex2) {
// no candidate destroy method found
}
}
}
return null;
}
return (StringUtils.hasLength(destroyMethodName) ? destroyMethodName : null);
}


执行顺序:

@Override

public void destroy() {

// bean

    if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {
// 执行@PreDestroy
for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {
processor.postProcessBeforeDestruction(this.bean, this.beanName);
}
}
//执行实现DisposableBean的destory方法
if (this.invokeDisposableBean) {
if (logger.isTraceEnabled()) {
logger.trace("Invoking destroy() on bean with name '" + this.beanName + "'");
}
try {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
((DisposableBean) this.bean).destroy();
return null;
}, this.acc);
}
else {
((DisposableBean) this.bean).destroy();
}
}
catch (Throwable ex) {
String msg = "Invocation of destroy method failed on bean with name '" + this.beanName + "'";
if (logger.isDebugEnabled()) {
logger.warn(msg, ex);
}
else {
logger.warn(msg + ": " + ex);
}
}
}

if (this.destroyMethod != null) {
invokeCustomDestroyMethod(this.destroyMethod);
}
else if (this.destroyMethodName != null) {
Method methodToInvoke = determineDestroyMethod(this.destroyMethodName);
if (methodToInvoke != null) {
invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(methodToInvoke));
}
}
}


1、 @preDestory

2、 实现了DisposableBean接口的Bean的destory方法

3、1 bean定义中destroyMethod 如xml中的 <bean id="aa" class="" init-method="initialize"destroy-method="cleanup"/>

当上面bean定义中destroyMethod 为空时候:

3、2

3.2.1 bean定义中destroyMethod == null

实现了DisposableBean接口的Bean的close方法

3.2.2 bean定义中destroyMethod == "(inferred)"

取close 方法 ,如果close 方法没有取shutdown 方法