依赖注入草稿
作者:互联网
加载类
实例化前 -----》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
public void test(){
System.out.println(this.orderService.getObject());
}
}
com.luban.service.OrderService@4cc451f2
com.luban.service.OrderService@294425a7
com.luban.service.OrderService@9f116cc
- 当注入的属性带有@Lazy注解,则会注入代理类。只有代理类调用方法的时候才会注入bean (才会执行doResolveDependency方法)
@Rsource
对于@Resource: - 如果@Resource注解中指定了name属性,那么则只会根据name属性的值去找bean,如果找不到则报错
- 如果@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的销毁过程
- 容器关闭
- 发布ContextClosedEvent事件
- 调用LifecycleProcessor的onClose方法
- 销毁单例Bean
- 找出所有DisposableBean(实现了DisposableBean接口的Bean)
- 遍历每个DisposableBean
- 找出依赖了当前DisposableBean的其他Bean,将这些Bean从单例池中移除掉
- 调用DisposableBean的destroy()方法
- 找到当前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