其他分享
首页 > 其他分享> > 依赖注入草稿

依赖注入草稿

作者:互联网

加载类
实例化前 -----》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方法 https://blog.csdn.net/lw_100831/article/details/42814995
思路:可以用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 https://www.cnblogs.com/binarylei/p/12337145.html#3-findautowirecandidates
认知一下,与依赖查找的相关 API:
resolveDependency:支持 Optional、延迟注入、懒加载注入、正常注入。
Spring依赖注入之注入Bean获取详解:https://blog.csdn.net/scjava/article/details/109276166
doResolveDependency:在依赖查找之前,想办法快速查找,
如缓存 beanName、@Value 等直接获取注入的值,避免通过类型查找,
最后才对集合依赖和单一依赖分别进行了处理。
实际上,无论是集合依赖还是单一依赖查找都是调用 findAutowireCandidates 方法。
findAutowireCandidates:真正在 Spring IoC 容器中进行依赖查找,
依赖查找的来源有三:①内部对象 ②托管Bean ③BeanDefinition。
最后如果无法查找到依赖对象,会进行一些补偿机制,想方设法获取注入的对象,如泛型补偿,自引用补偿。
isAutowireCandidate:判断候选对象是否可用,
有三重过滤规则:①bd.autowireCandidate=true -> ②泛型匹配 -> ③@Qualifier。委托给 ContextAnnotationAutowireCandidateResolver。
泛型匹配的demo:
https://blog.csdn.net/qingpengshan/article/details/80587452 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获取详解 https://blog.csdn.net/scjava/article/details/109276166

从源码分析@Qualifier,@Primary,@Priority的候选顺序
@Primary、@Priority、@Qualifier的用法??https://blog.csdn.net/z69183787/article/details/110638883

自己注入自己
定义一个类,类里面提供了一个构造方法,用来设置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的销毁:
https://blog.csdn.net/scjava/article/details/109276324
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;
	//		https://blog.csdn.net/scjava/article/details/109276324
	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 方法

标签:依赖,草稿,Bean,destroyMethodName,bean,null,public,注入
来源: https://www.cnblogs.com/tangliMeiMei/p/15291650.html