文章目录
- 一、目标:通过注解注入属性信息
- 二、设计:通过注解注入属性信息
- 三、实现:通过注解注入属性信息
- 3.1 工程结构
- 3.2 自动扫描注入占位符配置和对象类图
- 3.3 读取属性并填充到容器中
- 3.3.1 定义解析字符串接口
- 3.3.2 配置Bean工厂添加解析器
- 3.3.3 抽象Bean工厂基类
- 3.3.4 填充字符串
- 3.4 自定义属性注入注解
- 3.4.1 定义注入对象注解
- 3.4.2 定义注入对象辅助注解
- 3.4.3 定义注入属性注解
- 3.5 扫描自定义注解
- 3.5.1 修改Bean工厂接口
- 3.5.2 抽象应用上下文
- 3.5.3 默认Bean工厂实现类
- 3.5.4 实例化感知对象处理
- 3.5.5 默认自动代理创建者
- 3.5.6 扫描自定义注解类
- 3.6 在Bean生命周期中属性注入
- 3.6.1 在对象工厂注册
- 3.6.2 在Bean生命周期内调用属性注入
- 四、测试:通过注解注入属性信息
- 4.1 添加测试配置
- 4.1.1 用户数据层类
- 4.1.2 用户服务层实现类
- 4.1.3 Spring属性配置文件
- 4.2 单元测试
- 五、总结:通过注解注入属性信息
一、目标:通过注解注入属性信息
💡 怎么完成自动注入属性?
- 我们已经解决需要手动配置 Bean 对象到
spring.xml
文件中,改为可以自动扫描带有注解@Component
的对象完成自动装配和注册到 Spring 容器的操作。 - 那么在自动扫描包注册 Bean 对象之后,就需要把原来在配置文件中通过
property name="token"
配置属性和 Bean 的操作,也改为可以自动注入。- 使用
@Autowired
、@Value
注解,完成对属性和对象的注入操作。
- 使用
二、设计:通过注解注入属性信息
💡 设计:简化注入属性,通过注解的形式自动化扫描注册。
- 在完成 Bean 对象的基础功能后,后续添加的功能都是围绕着 Bean 的生命周期进行的。比如:
- 修改 Bean 的定义
BeanFactoryPostProcessor
。 - 处理 Bean 的属性要用到
BeanPostProcessor
。 - 完成个性的属性操作则专门继承
BeanPostProcessor
提供新的接口。
- 修改 Bean 的定义
- 因为这样才能通过
instanceof
判断出具有标记性的接口,所以关于 Bean 等等的操作,以及监听Aware
、获取BeanFactory
,都需要在 Bean 的生命周期中完成。 - 设计:属性和 Bean 对象的注入,也会用到
BeanPostProcessor
来完成在设置 Bean 属性之前,允许BeanPostProcessor
修改属性值。
- 要处理自动扫描注入,包括属性注入、对象注入,则需要在对象属性
applyPropertyValues
填充之前,把属性信息写入到PropertyValues
的集合中去。- 这一步相当于:解决之前在
spring.xml
配置属性的过程。
- 这一步相当于:解决之前在
- 而在属性的读取中,需要依赖于对 Bean 对象的类中属性配置了注解的扫描。
field.getAnnotation(Value.class)
。依次拿出符合的属性并填充上相应的配置信息。- 属性的配置信息需要依赖于
BeanFactoryPostProcessor
的实现类PropertyPlaceholderConfigurer
,把值写入到AbstractBeanFactory#embeddedValueResolvers
集合中,这样才能在属性填充中利用beanFactory
获取相应的属性值。
@Autowired
对于对象的注入,这一个和属性注入的唯一区别是对于对象的获取beanFactory.getBean(fieldType)
。- 当所有的属性被设置到
PropertyValues
完成以后,接下来就是创建对象的下一步,属性填充。此时就会把我们获取到的配置和对象填充到属性上,也就实现了自动注入的功能。
三、实现:通过注解注入属性信息
3.1 工程结构
spring-step-14
|-src|-main| |-java| |-com.lino.springframework| |-aop| | |-aspectj| | | |-AspectJExpressionPointcut.java| | | |-AspectJExpressionPointcutAdvisor.java| | |-framework| | | |-adapter| | | | |-MethodBeforeAdviceInterceptor.java| | | |-autoproxy| | | | |-DefaultAdvisorAutoProxyCreator.java| | | |-AopProxy.java| | | |-Cglib2AopProxy.java| | | |-JdkDynamicAopProxy.java| | | |-ProxyFactory.java| | | |-ReflectiveMethodInvocation.java| | |-AdvisedSupport.java| | |-Advisor.java| | |-BeforeAdvice.java| | |-ClassFilter.java| | |-MethodBeforeAdvice.java| | |-MethodMatcher.java| | |-Pointcut.java| | |-PointcutAdvisor.java| | |-TargetSource.java| |-beans| | |-factory| | | |-annotation| | | | |-Autowired.java| | | | |-AutowiredAnnotationBeanPostProcessor.java| | | | |-Qualifier.java| | | | |-Value.java| | | |-config| | | | |-AutowireCapableBeanFactory.java| | | | |-BeanDefinition.java| | | | |-BeanFactoryPostProcessor.java| | | | |-BeanPostProcessor.java| | | | |-BeanReference.java| | | | |-ConfigurableBeanFactory.java| | | | |-InstantiationAwareBeanPostProcessor.java| | | | |-SingletonBeanRegistry.java| | | |-support| | | | |-AbstractAutowireCapableBeanFactory.java| | | | |-AbstractBeabDefinitionReader.java| | | | |-AbstractBeabFactory.java| | | | |-BeabDefinitionReader.java| | | | |-BeanDefinitionRegistry.java| | | | |-CglibSubclassingInstantiationStrategy.java| | | | |-DefaultListableBeanFactory.java| | | | |-DefaultSingletonBeanRegistry.java| | | | |-DisposableBeanAdapter.java| | | | |-FactoryBeanRegistrySupport.java| | | | |-InstantiationStrategy.java| | | | |-SimpleInstantiationStrategy.java| | | |-xml| | | | |-XmlBeanDefinitionReader.java| | | |-Aware.java| | | |-BeanClassLoaderAware.java| | | |-BeanFactory.java| | | |-BeanFactoryAware.java| | | |-BeanNameAware.java| | | |-ConfigurableListableBeanFactory.java| | | |-DisposableBean.java| | | |-FactoryBean.java| | | |-HierarcgicalBeanFactory.java| | | |-InitializingBean.java| | | |-ListableBeanFactory.java| | | |-PropertyPlaceholderConfigurer.java| | |-BeansException.java| | |-PropertyValue.java| | |-PropertyValues.java| |-context| | |-annotation| | | |-ClassPathBeanDefinitionScanner.java| | | |-ClassPathScanningCandidateComponentProvider.java| | | |-Scope.java| | |-event| | | |-AbstractApplicationEventMulticaster.java| | | |-ApplicationContextEvent.java| | | |-ApplicationEventMulticaster.java| | | |-ContextclosedEvent.java| | | |-ContextRefreshedEvent.java| | | |-SimpleApplicationEventMulticaster.java| | |-support| | | |-AbstractApplicationContext.java| | | |-AbstractRefreshableApplicationContext.java| | | |-AbstractXmlApplicationContext.java| | | |-ApplicationContextAwareProcessor.java| | | |-ClassPathXmlApplicationContext.java| | |-ApplicationContext.java| | |-ApplicationContextAware.java| | |-ApplicationEvent.java| | |-ApplicationEventPublisher.java| | |-ApplicationListener.java| | |-ConfigurableApplicationContext.java| |-core.io| | |-ClassPathResource.java| | |-DefaultResourceLoader.java| | |-FileSystemResource.java| | |-Resource.java| | |-ResourceLoader.java| | |-UrlResource.java| |-stereotype| | |-Component.java| |-util| | |-ClassUtils.java| | |-StringValueResolver.java|-test|-java|-com.lino.springframework.test|-bean| |-IUserService.java| |-UserDao.java| |-UserService.java|-ApiTest.java|-resources|-spring.xml|-token.properties
3.2 自动扫描注入占位符配置和对象类图
- 在整个类图中围绕接口
InstantiationAwareBeanPostProcessor
的类AutowiredAnnotationBeanPostProcessor
作为入口点。- 在
AbstractAutowireCapableBeanFactory
创建 Bean 对象过程中。 - 调用扫描整个类的属性配置中含有自定义注解
Value
、Autowired
、Qualifier
的属性值。
- 在
- 关于属性值信息的获取,在注解配置的属性字段扫描到信息注入时。
- 包括了占位符从配置文件获取信息,也包括 Bean 对象。
- Bean 对象可以直接获取,但配置信息需要在
AbstractBeanFactory
中添加新的属性集合embeddedValueResolvers
,由PropertyPlaceholderConfigurer#postProcessBeanFactory
进行操作填充到属性集合中。
3.3 读取属性并填充到容器中
3.3.1 定义解析字符串接口
StringValueResolver.java
package com.lino.springframework.util;/*** @description: 解析字符串接口*/
public interface StringValueResolver {/*** 解析字符串** @param strVal 字符串* @return 解析后的结果*/String resolveStringValue(String strVal);
}
3.3.2 配置Bean工厂添加解析器
ConfigurableBeanFactory.java
package com.lino.springframework.beans.factory.config;import com.lino.springframework.beans.factory.HierarchicalBeanFactory;
import com.lino.springframework.util.StringValueResolver;/*** @description: 配置Bean工厂接口*/
public interface ConfigurableBeanFactory extends HierarchicalBeanFactory, SingletonBeanRegistry {String SCOPE_SINGLETON = "singleton";String SCOPE_PROTOTYPE = "prototype";/*** 添加修改新实例化 Bean 对象的扩展点** @param beanPostProcessor 新实例化 Bean 对象*/void addBeanPostProcessor(BeanPostProcessor beanPostProcessor);/*** 销毁单例*/void destroySingletons();/*** 添加字符串解析器** @param valueResolver 解析器*/void addEmbeddedValueResolver(StringValueResolver valueResolver);/*** 解析嵌入值** @param value 嵌入值* @return 解析后的结果*/String resolveEmbeddedValue(String value);
}
3.3.3 抽象Bean工厂基类
AbstractBeanFactory.java
package com.lino.springframework.beans.factory.support;import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.factory.FactoryBean;
import com.lino.springframework.beans.factory.config.BeanDefinition;
import com.lino.springframework.beans.factory.config.BeanPostProcessor;
import com.lino.springframework.beans.factory.config.ConfigurableBeanFactory;
import com.lino.springframework.util.ClassUtils;
import com.lino.springframework.util.StringValueResolver;
import java.util.ArrayList;
import java.util.List;/*** @description: 抽象的 Bean 工厂基类,定义模板方法*/
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();private final List<BeanPostProcessor> beanPostProcessors = new ArrayList<>();private final List<StringValueResolver> embeddedValueResolvers = new ArrayList<>();...@Overridepublic void addEmbeddedValueResolver(StringValueResolver valueResolver) {this.embeddedValueResolvers.add(valueResolver);}@Overridepublic String resolveEmbeddedValue(String value) {String result = value;for (StringValueResolver resolver : this.embeddedValueResolvers) {result = resolver.resolveStringValue(result);}return result;}...
}
3.3.4 填充字符串
PropertyPlaceholderConfigurer.java
package com.lino.springframework.beans.factory;import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.PropertyValue;
import com.lino.springframework.beans.PropertyValues;
import com.lino.springframework.beans.factory.config.BeanDefinition;
import com.lino.springframework.beans.factory.config.BeanFactoryPostProcessor;
import com.lino.springframework.core.io.DefaultResourceLoader;
import com.lino.springframework.core.io.Resource;
import com.lino.springframework.util.StringValueResolver;
import java.io.IOException;
import java.util.Properties;/*** @description: 处理占位符配置类*/
public class PropertyPlaceholderConfigurer implements BeanFactoryPostProcessor {/*** 占位符前缀*/public static final String DEFAULT_PLACEHOLDER_PREFIX = "${";/*** 占位符后缀*/public static final String DEFAULT_PLACEHOLDER_SUFFIX = "}";private String location;@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {try {// 加载属性文件DefaultResourceLoader resourceLoader = new DefaultResourceLoader();Resource resource = resourceLoader.getResource(location);// 占位符替换属性值Properties properties = new Properties();properties.load(resource.getInputStream());String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();for (String beanName : beanDefinitionNames) {BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);PropertyValues propertyValues = beanDefinition.getPropertyValues();for (PropertyValue propertyValue : propertyValues.getPropertyValues()) {Object value = propertyValue.getValue();if (!(value instanceof String)) {continue;}value = resolvePlaceholder((String) value, properties);propertyValues.addPropertyValue(new PropertyValue(propertyValue.getName(), value));}}// 向容器中添加字符串解析器,共解析@Value注解使用StringValueResolver valueResolver = new PlaceholderResolvingStringValueResolver(properties);beanFactory.addEmbeddedValueResolver(valueResolver);} catch (IOException e) {throw new BeansException("Could not load properties", e);}}private String resolvePlaceholder(String value, Properties properties) {String strVal = value;StringBuilder buffer = new StringBuilder(strVal);int startIdx = strVal.indexOf(DEFAULT_PLACEHOLDER_PREFIX);int stopIdx = strVal.indexOf(DEFAULT_PLACEHOLDER_SUFFIX);if (startIdx != -1 && stopIdx != -1 && startIdx < stopIdx) {String propKey = strVal.substring(startIdx + 2, stopIdx);String propVal = properties.getProperty(propKey);buffer.replace(startIdx, stopIdx + 1, propVal);}return buffer.toString();}public void setLocation(String location) {this.location = location;}private class PlaceholderResolvingStringValueResolver implements StringValueResolver {private Properties properties;public PlaceholderResolvingStringValueResolver(Properties properties) {this.properties = properties;}@Overridepublic String resolveStringValue(String strVal) {return PropertyPlaceholderConfigurer.this.resolvePlaceholder(strVal, properties);}}
}
- 在解析属性配置的类
PropertyPlaceholderConfigurer
中,最重要的是beanFactory.addEmbeddedValueResolver(valueResolver)
。- 这是把属性值写入到了
AbstractBeanFactory
的embeddedValueResolvers
集合中。 embeddedValueResolvers
是在AbstractBeanFactory
类新增加的集合List<StringValueResolver> embeddedValueResolvers
。
- 这是把属性值写入到了
3.4 自定义属性注入注解
3.4.1 定义注入对象注解
Autowired.java
package com.lino.springframework.beans.factory.annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** @description: 注入对象注解*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD})
public @interface Autowired {
}
3.4.2 定义注入对象辅助注解
Qualifier.java
package com.lino.springframework.beans.factory.annotation;import java.lang.annotation.*;/*** @description: 注入对象辅助注解*/
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Qualifier {String value() default "";
}
Qualifier
一般与Autowired
搭配使用。
3.4.3 定义注入属性注解
Value.java
package com.lino.springframework.beans.factory.annotation;import java.lang.annotation.*;/*** @description: 注入属性注解*/
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Value {/*** The actual value expression: e.g. "#{systemProperties.myProp}".*/String value();
}
3.5 扫描自定义注解
3.5.1 修改Bean工厂接口
BeanFactory.java
package com.lino.springframework.beans.factory;import com.lino.springframework.beans.BeansException;/*** @description: 定义 Bean 工厂接口*/
public interface BeanFactory {/*** 返回 Bean 的实例对象** @param name 要检索的bean的名称* @return 实例化的 Bean 对象* @throws BeansException 不能获取 Bean 对象,抛出异常*/Object getBean(String name) throws BeansException;/*** 返回含构造函数的 Bean 实例对象** @param name 要检索的bean的名称* @param args 构造函数入参* @return 实例化的 Bean 对象* @throws BeansException 不能获取 Bean 对象,抛出异常*/Object getBean(String name, Object... args) throws BeansException;/*** 返回指定泛型的对象** @param name 要检索的bean的名称* @param requiredType 类型* @param <T> 泛型* @return 实例化的的 Bean 对象* @throws BeansException 不能获取 Bean 对象,抛出异常*/<T> T getBean(String name, Class<T> requiredType) throws BeansException;/*** 返回指定泛型的对象** @param requiredType 类型* @param <T> 泛型* @return 实例化的的 Bean 对象* @throws BeansException 不能获取 Bean 对象,抛出异常*/<T> T getBean(Class<T> requiredType) throws BeansException;
}
- 添加
getBean(Class<T> requiredType)
方法
3.5.2 抽象应用上下文
AbstractApplicationContext.java
package com.lino.springframework.context.support;import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.factory.ConfigurableListableBeanFactory;
import com.lino.springframework.beans.factory.config.BeanFactoryPostProcessor;
import com.lino.springframework.beans.factory.config.BeanPostProcessor;
import com.lino.springframework.context.ApplicationEvent;
import com.lino.springframework.context.ApplicationListener;
import com.lino.springframework.context.ConfigurableApplicationContext;
import com.lino.springframework.context.event.ApplicationEventMulticaster;
import com.lino.springframework.context.event.ContextClosedEvent;
import com.lino.springframework.context.event.ContextRefreshedEvent;
import com.lino.springframework.context.event.SimpleApplicationEventMulticaster;
import com.lino.springframework.core.io.DefaultResourceLoader;
import java.util.Collection;
import java.util.Map;/*** @description: 抽象应用上下文*/
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {...@Overridepublic Object getBean(String name) throws BeansException {return getBeanFactory().getBean(name);}@Overridepublic Object getBean(String name, Object... args) throws BeansException {return getBeanFactory().getBean(name, args);}@Overridepublic <T> T getBean(String name, Class<T> requiredType) throws BeansException {return getBeanFactory().getBean(name, requiredType);}@Overridepublic <T> T getBean(Class<T> requiredType) throws BeansException {return getBeanFactory().getBean(requiredType);}...}
- 添加
getBean(Class<T> requiredType)
方法实现
3.5.3 默认Bean工厂实现类
DefaultListableBeanFactory.java
package com.lino.springframework.beans.factory.support;import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.factory.ConfigurableListableBeanFactory;
import com.lino.springframework.beans.factory.config.BeanDefinition;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** @description: 默认的Bean工厂实现类*/
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements BeanDefinitionRegistry, ConfigurableListableBeanFactory {...@Overridepublic <T> T getBean(Class<T> requiredType) throws BeansException {List<String> beanNames = new ArrayList<>();for (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()) {Class beanClass = entry.getValue().getBeanClass();if (requiredType.isAssignableFrom(beanClass)) {beanNames.add(entry.getKey());}}if (1 == beanNames.size()) {return getBean(beanNames.get(0), requiredType);}throw new BeansException(requiredType + "expected single bean but found " + beanNames.size() + ": " + beanNames);}
}
- 添加
getBean(Class<T> requiredType)
方法实现
3.5.4 实例化感知对象处理
InstantiationAwareBeanPostProcessor.java
package com.lino.springframework.beans.factory.config;import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.PropertyValues;/*** @description: 实例化感知对象处理*/
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {/*** 在 Bean 对象执行初始化方法之前,执行此方法** @param beanClass 对象类* @param beanName 对象名* @return 新对象* @throws BeansException 异常*/Object postProcessBeforeInitialization(Class<?> beanClass, String beanName) throws BeansException;/*** 在 Bean 对象实例化完成后,设置属性操作之前执行此方法** @param pvs 属性值集合* @param bean 对象* @param beanName 对象名称* @return 属性值集合* @throws BeansException 异常*/PropertyValues postProcessPropertyValues(PropertyValues pvs, Object bean, String beanName) throws BeansException;
}
- 添加
postProcessPropertyValues
方法
3.5.5 默认自动代理创建者
DefaultAdvisorAutoProxyCreator.java
package com.lino.springframework.aop.framework.autoproxy;import com.lino.springframework.aop.*;
import com.lino.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor;
import com.lino.springframework.aop.framework.ProxyFactory;
import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.PropertyValues;
import com.lino.springframework.beans.factory.BeanFactory;
import com.lino.springframework.beans.factory.BeanFactoryAware;
import com.lino.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import com.lino.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInterceptor;
import java.util.Collection;/*** @description: 默认自动代理创建者*/
public class DefaultAdvisorAutoProxyCreator implements InstantiationAwareBeanPostProcessor, BeanFactoryAware {private DefaultListableBeanFactory beanFactory;...@Overridepublic PropertyValues postProcessPropertyValues(PropertyValues pvs, Object bean, String beanName) throws BeansException {return pvs;}...
}
- 添加
postProcessPropertyValues
默认实现
3.5.6 扫描自定义注解类
AutowiredAnnotationBeanPostProcessor.java
package com.lino.springframework.beans.factory.annotation;import cn.hutool.core.bean.BeanUtil;
import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.PropertyValues;
import com.lino.springframework.beans.factory.BeanFactory;
import com.lino.springframework.beans.factory.BeanFactoryAware;
import com.lino.springframework.beans.factory.config.ConfigurableBeanFactory;
import com.lino.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import com.lino.springframework.util.ClassUtils;
import java.lang.reflect.Field;/*** @description: 扫描自定义注解类*/
public class AutowiredAnnotationBeanPostProcessor implements InstantiationAwareBeanPostProcessor, BeanFactoryAware {private ConfigurableBeanFactory beanFactory;@Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {this.beanFactory = (ConfigurableBeanFactory) beanFactory;}@Overridepublic PropertyValues postProcessPropertyValues(PropertyValues pvs, Object bean, String beanName) throws BeansException {// 1.处理注解 @ValueClass<?> clazz = bean.getClass();clazz = ClassUtils.isCglibProxyClass(clazz) ? clazz.getSuperclass() : clazz;Field[] declaredFields = clazz.getDeclaredFields();for (Field field : declaredFields) {Value valueAnnotation = field.getAnnotation(Value.class);if (null != valueAnnotation) {String value = valueAnnotation.value();value = beanFactory.resolveEmbeddedValue(value);BeanUtil.setFieldValue(bean, field.getName(), value);}}// 2.处理注解 @Autowiredfor (Field field : declaredFields) {Autowired autowiredAnnotation = field.getAnnotation(Autowired.class);if (null != autowiredAnnotation) {Class<?> fieldType = field.getType();String dependentBeanName = null;Qualifier qualifierAnnotation = field.getAnnotation(Qualifier.class);Object dependentBean = null;if (null != qualifierAnnotation) {dependentBeanName = qualifierAnnotation.value();dependentBean = beanFactory.getBean(dependentBeanName, fieldType);} else {dependentBean = beanFactory.getBean(fieldType);}BeanUtil.setFieldValue(bean, field.getName(), dependentBean);}}return pvs;}@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {return null;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {return null;}@Overridepublic Object postProcessBeforeInitialization(Class<?> beanClass, String beanName) throws BeansException {return null;}
}
AutowiredAnnotationBeanPostProcessor
是实现接口InstantiationAwareBeanPostProcessor
的一个用于在 Bean 对象实例化完成后,设置属性操作前的处理属性信息的类和操作方法。- 只有实现了
BeanPostFactory
接口才有机会在 Bean 的生命周期中处理初始化信息。
- 只有实现了
- 核心方法
postProcessPropertyValues
,主要用于处理类含有@Value
、@Autowired
注解的属性,进行属性信息的提取和设置。 - 注意:因为在
AbstractAutowireCapableBeanFactory
类中使用的是CglibSubclassingInstantiationStrategy
进行类的创建,所以在AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues
中需要判断是否为 CGLIB 创建对象,否则是不能拿到类信息的。ClassUtils.isCglibProxyClass(clazz) ? clazz.getSuperclass() : clazz
3.6 在Bean生命周期中属性注入
3.6.1 在对象工厂注册
ClassPathBeanDefinitionScanner.java
package com.lino.springframework.context.annotation;import cn.hutool.core.util.StrUtil;
import com.lino.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import com.lino.springframework.beans.factory.config.BeanDefinition;
import com.lino.springframework.beans.factory.support.BeanDefinitionRegistry;
import com.lino.springframework.stereotype.Component;
import java.util.Set;/*** @description: 类路径扫描装配实现类*/
public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {private BeanDefinitionRegistry registry;public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {this.registry = registry;}public void doScan(String... basePackages) {for (String basePackage : basePackages) {Set<BeanDefinition> candidates = findCandidateComponents(basePackage);for (BeanDefinition beanDefinition : candidates) {// 解析 bean 的作用域 singleton、prototypeString beanScope = resolveBeanScope(beanDefinition);if (StrUtil.isNotEmpty(beanScope)) {beanDefinition.setScope(beanScope);}registry.registerBeanDefinition(determineBeanName(beanDefinition), beanDefinition);}}// 注册处理注解的 BeanPostProcessor(@AutoWired、@Value)registry.registerBeanDefinition("com.lino.springframework.context.annotation.internalAutowiredAnnotationProcessor", new BeanDefinition(AutowiredAnnotationBeanPostProcessor.class));}...
}
- 由于
AutowiredAnnotationBeanPostProcessor
并没有标注@Component
,所以无法在类扫描时注入到beanFactory
中,此处需要手动注册。
3.6.2 在Bean生命周期内调用属性注入
AbstractAutowireCapableBeanFactory.java
package com.lino.springframework.beans.factory.support;import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.PropertyValue;
import com.lino.springframework.beans.PropertyValues;
import com.lino.springframework.beans.factory.*;
import com.lino.springframework.beans.factory.config.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;/*** @description: 实现默认bean创建的抽象bean工厂超类*/
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();@Overrideprotected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) {Object bean = null;try {// 判断是否返回代理 Bean 对象bean = resolveBeforeInstantiation(beanName, beanDefinition);if (null != bean) {return bean;}// 实例化Beanbean = createBeanInstance(beanDefinition, beanName, args);// 在设置Bean属性之前,允许 BeanPostProcessor修改属性值applyBeanPostProcessorsBeforeApplyingPropertyValues(beanName, bean, beanDefinition);// 给bean填充属性applyPropertyValues(beanName, bean, beanDefinition);// 执行 Bean 的初始化方法和 BeanPostProcessor 的前置和后置处理方法bean = initializeBean(beanName, bean, beanDefinition);} catch (Exception e) {throw new BeansException("Instantiation of bean failed", e);}// 注册实现 DisposableBean 接口的 Bean 对象registerDisposableBeanIfNecessary(beanName, bean, beanDefinition);// 判断 SCOPE_SINGLETON、SCOPE_PROTOTYPEif (beanDefinition.isSingleton()) {registerSingletonBean(beanName, bean);}return bean;}.../*** 在设置 Bean 属性之前,允许 BeanPostProcessor 修改属性值** @param beanName 对象名称* @param bean 对象* @param beanDefinition 实例化对象*/private void applyBeanPostProcessorsBeforeApplyingPropertyValues(String beanName, Object bean, BeanDefinition beanDefinition) {for (BeanPostProcessor beanPostProcessor : getBeanPostProcessors()) {if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {PropertyValues pvs = ((InstantiationAwareBeanPostProcessor) beanPostProcessor).postProcessPropertyValues(beanDefinition.getPropertyValues(), bean, beanName);if (null != pvs) {for (PropertyValue propertyValue : pvs.getPropertyValues()) {beanDefinition.getPropertyValues().addPropertyValue(propertyValue);}}}}}...
}
AbstractAutowireCapableBeanFactory#createBean
方法中有这一条新增加的方法调用,就是:- 设置 Bean 属性之前,允许 BeanPostProcessor 修改属性值。
applyBeanPostProcessorsBeforeApplyingPropertyValues
- 在这个方法中,首先就是获取已经注入的
BeanPostProcessor
集合并从中筛选出继承接口InstantiationAwareBeanPostProcessor
的实现类。 - 最后就是调用相应的
postProcessPropertyValues
方法以及循环设置属性值信息。beanDefinition.getPropertyValues().addPropertyValue(propertyValue)
- 在这个方法中,首先就是获取已经注入的
四、测试:通过注解注入属性信息
4.1 添加测试配置
4.1.1 用户数据层类
UserDao.java
package com.lino.springframework.test.bean;import com.lino.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;/*** @description: 用户DAO层*/
@Component
public class UserDao {private static Map<String, String> hashMap = new HashMap<>();static {hashMap.put("10001", "张三,浙江,杭州");hashMap.put("10002", "李四,上海,尖沙咀");hashMap.put("10003", "王五,香港,铜锣湾");}public String queryUserName(String uId) {return hashMap.get(uId);}
}
- 给类配置上一个自动扫描注册 Bean 对象的注解
@Component
,接下来会把这个类注入到UserService
中。
4.1.2 用户服务层实现类
UserService.java
package com.lino.springframework.test.bean;import com.lino.springframework.beans.factory.annotation.Autowired;
import com.lino.springframework.beans.factory.annotation.Value;
import com.lino.springframework.stereotype.Component;
import java.util.Random;/*** @description: 用户接口实现类*/
@Component("userService")
public class UserService implements IUserService {@Value("${token}")private String token;@Autowiredprivate UserDao userDao;@Overridepublic String queryUserInfo() {try {Thread.sleep(new Random(1).nextInt(100));} catch (InterruptedException e) {e.printStackTrace();}return userDao.queryUserName("10001") + ", " + token;}@Overridepublic String register(String userName) {try {Thread.sleep(new Random(1).nextInt(100));} catch (InterruptedException e) {e.printStackTrace();}return "注册用户:" + userName + " success!";}@Overridepublic String toString() {return "UserService#token = {" + token + "}";}public String getToken() {return token;}public void setToken(String token) {this.token = token;}public UserDao getUserDao() {return userDao;}public void setUserDao(UserDao userDao) {this.userDao = userDao;}
}
- 这里包括了两种类型的注入,一个是占位符注入属性信息
@Value("${token}")
,另外一个是注入对象信息@Autowired
。
4.1.3 Spring属性配置文件
spring.xml
<?xml version="1.0" encoding="utf-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context"><bean class="com.lino.springframework.beans.factory.PropertyPlaceholderConfigurer"><property name="location" value="classpath:token.properties"/></bean><context:component-scan base-package="com.lino.springframework.test.bean"/></beans>
4.2 单元测试
ApiTest.java
@Test
public void test_scan() {ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml");IUserService userService = applicationContext.getBean("userService", IUserService.class);System.out.println("测试结果:" + userService.queryUserInfo());
}
- 单元测试时,可以完整的测试一个类注入到 Spring 容器,同时这个属性信息也可以被自动扫描填充。
测试结果
测试结果:张三,浙江,杭州, RejDlI78hu223Opo983Ds
- 测试结果看,使用方式已经通过了,有自动扫描类,有注解注入属性。
五、总结:通过注解注入属性信息
- 从整个注解信息扫描注入的实现内容看,我们围绕着在 Bean 的生命周期中进行处理。
- 就像 BeanPostProcessor 用于修改新实例化 Bean 对象的扩展点。
- 提供的接口方法可以用于处理 Bean 对象实例化前后进行处理操作。
- 而有时候需要做一些差异化的控制,所以还需要继承
BeanPostProcessor
接口。- 定义新的接口
InstantiationAwareBeanPostProcessor
这样就可以区分出不同扩展点的操作。
- 定义新的接口
- 像是接口
instanceof
判断,注解用field.getAnnotation(Value.class)
获取,都是相当于在类上做的一些标识性信息,便于可以用一些方法找到这些功能点,以便进行处理。