文章目录
- 一、目标:通过注解注入属性信息
- 二、设计:通过注解注入属性信息
- 三、实现:通过注解注入属性信息
- 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<>();
...
@Override
public void addEmbeddedValueResolver(StringValueResolver valueResolver) {
this.embeddedValueResolvers.add(valueResolver);
}
@Override
public 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;
@Override
public 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;
}
@Override
public 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 {
...
@Override
public Object getBean(String name) throws BeansException {
return getBeanFactory().getBean(name);
}
@Override
public Object getBean(String name, Object... args) throws BeansException {
return getBeanFactory().getBean(name, args);
}
@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
return getBeanFactory().getBean(name, requiredType);
}
@Override
public <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 {
...
@Override
public <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;
...
@Override
public 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;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = (ConfigurableBeanFactory) beanFactory;
}
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs, Object bean, String beanName) throws BeansException {
// 1.处理注解 @Value
Class<?> 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.处理注解 @Autowired
for (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;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return null;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return null;
}
@Override
public 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、prototype
String 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();
@Override
protected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) {
Object bean = null;
try {
// 判断是否返回代理 Bean 对象
bean = resolveBeforeInstantiation(beanName, beanDefinition);
if (null != bean) {
return bean;
}
// 实例化Bean
bean = 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_PROTOTYPE
if (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;
@Autowired
private UserDao userDao;
@Override
public String queryUserInfo() {
try {
Thread.sleep(new Random(1).nextInt(100));
} catch (InterruptedException e) {
e.printStackTrace();
}
return userDao.queryUserName("10001") + ", " + token;
}
@Override
public String register(String userName) {
try {
Thread.sleep(new Random(1).nextInt(100));
} catch (InterruptedException e) {
e.printStackTrace();
}
return "注册用户:" + userName + " success!";
}
@Override
public 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/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://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)
获取,都是相当于在类上做的一些标识性信息,便于可以用一些方法找到这些功能点,以便进行处理。