上回书我们就说到要用@Value来取代spring配置, 顺便手撸一下@Autowired 其实很简单,撸完加深了对注解开发的理解
三个注解
都在这个目录下
package com.linnine.spring.beans.factory.annotation;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.CONSTRUCTOR,ElementType.FIELD,ElementType.METHOD})
public @interface Autowired {
}
/**
* 用于配合Autowire的使用 限定名称
*/
@Target({ElementType.FIELD,ElementType.METHOD,ElementType.PARAMETER,ElementType.TYPE,ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Qualifier {
String value() default "";
}
@Target({ElementType.FIELD,ElementType.METHOD,ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Value {
String value();
}
AutowiredAnnotationBeanPostProcessor
然后就是对这三个注解的处理,等下给他爹加个抽象方法
package com.linnine.spring.beans.factory.annotation;
public class AutowiredAnnotationBeanPostProcessor implements InstantiationAwareBeanPostProcessor, BeanFactoryAware {
private ConfigurableListableBeanFactory beanFactory;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
}
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs,Object bean,String beanName) throws BeansException{
Class<?> clazz = bean.getClass();
//判断是否被代理的类 这块代码在下面
clazz = ClassUtils.isCglibProxyClass(clazz)?clazz.getSuperclass():clazz;
//获取类所有声明的字段 包括public private protect
Field[] declaredFields = clazz.getDeclaredFields();
//处理@Value
for (Field field : declaredFields) {
// 看这个字段是否有大@Value注解
Value valueAnnotation = field.getAnnotation(Value.class);
if (null != valueAnnotation){
String value = valueAnnotation.value();
//解析字符串 如占位符替换成值
value = beanFactory.resolveEmbeddedValue(value);
//把值塞到这个对象的这个属性里
BeanUtil.setFieldValue(bean,field.getName(),value);
}
}
//处理 @Autowired
for (Field field : declaredFields) {
Autowired autowiredAnnotation = field.getAnnotation(Autowired.class);
if (null!= autowiredAnnotation){
Class<?> fieldType = field.getType();
String dependentBeanName;
//看是否有指定bean名称
Qualifier qualifierAnnotation = field.getAnnotation(Qualifier.class);
Object dependentBean;
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 postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
return null;
}
}
InstantiationAwareBeanPostProcessor
增加一个属性填充前的方法
package com.linnine.spring.beans.factory.config;
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor{
/**
* 在 Bean 对象执行初始化方法之前,执行此方法
* @param beanClass
* @param beanName
* @return
* @throws BeansException
*/
Object postProcessBeforeInstantiation(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;
}
ClassPathBeanDefinitionScanner
然后注册一下这个后处理
public void doScan(String... basePackages){
...省略
// 注册处理注解的 BeanPostProcessor(@Autowired、@Value)
registry.registerBeanDefinition("internalAutowiredAnnotationProcessor",new BeanDefinition(AutowiredAnnotationBeanPostProcessor.class));
}
ClassUtils
工具类
package com.linnine.spring.utils;
public class ClassUtils {
public static ClassLoader getDefaultClassLoader() {
ClassLoader cl = null;
try {
cl = Thread.currentThread().getContextClassLoader();
}
catch (Throwable ex) {
// Cannot access thread context ClassLoader - falling back to system class loader...
}
if (cl == null) {
// No thread context class loader -> use class loader of this class.
cl = ClassUtils.class.getClassLoader();
}
return cl;
}
public static boolean isCglibProxyClass(Class<?> clazz) {
return clazz!=null && isCglibProxyClassName(clazz.getName());
}
public static boolean isCglibProxyClassName(String className) {
return className!=null && className.contains("$$");
}
}
StringValueResolver
开一个字符串解析接口
package com.linnine.spring.utils;
/**
* 字符串解析
*/
public interface StringValueResolver {
String resolveStringValue(String strVal);
}
PropertyPlaceholderConfigurer
之前的value占位符注入主要是解析xml配置文件的, 所以需要整合提取一下
package com.linnine.spring.beans.factory;
@Data
public class PropertyPlaceholderConfigurer implements BeanFactoryPostProcessor {
/**
* 读取 占位符 格式 ${value}
*/
private static final String DEFAULT_PLACEHOLDER_PREFIX = "${";
private static final String DEFAULT_PLACEHOLDER_SUFFIX = "}";
private String location;
@Override
public void postProcessorBeanFactory(ConfigurableListableBeanFactory beanFactory) {
//加载属性文件
DefaultResourceLoader resourceLoader = new DefaultResourceLoader();
Resource resource = resourceLoader.getResource(location);
Properties properties = new Properties();
try {
//加载配置信息
properties.load(resource.getInputStream());
//获取所有bean定义名
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));
}
}
//将配置信息存进去以供转换
StringValueResolver valueResolver = new PlaceholderResolvingStringValueResolver(properties);
beanFactory.addEmbeddedValueResolver(valueResolver);
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
/**
* 方法提取出来 对占位符进行处理
* @param strVal
* @param properties
* @return
*/
private String resolvePlaceholder(String strVal, Properties properties) {
StringBuilder builder = 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);
//替换
builder.replace(startIdx, stopIdx + 1, propVal);
}
return builder.toString();
}
private class PlaceholderResolvingStringValueResolver implements StringValueResolver {
private final Properties properties;
private PlaceholderResolvingStringValueResolver(Properties properties) {
this.properties = properties;
}
@Override
public String resolveStringValue(String strVal) {
return PropertyPlaceholderConfigurer.this.resolvePlaceholder(strVal, properties);
}
}
}
AbstractBeanFactory
管理一下这些字符串解析处理类
/**
* 15 新增 字符串解析(如解析占位符替换)
*/
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;
}
ConfigurableBeanFactory
上面重写的接口定义在这里
void addEmbeddedValueResolver(StringValueResolver valueResolver);
String resolveEmbeddedValue(String value);
AbstractAutowireCapableBeanFactory
在bean实例化后 调用一下我们准备的那些注解扫描注入填充到属性中
protected 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);
}
}
}
}
}
BeanFactory
补充一个根据class获取bean的方法
<T> T getBean(Class<T> requiredType) throws BeansException;
DefaultListableBeanFactory
实现
@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);
}
AbstractApplicationContext
调用
@Override
public <T> T getBean(Class<T> requiredType) throws BeansException {
return getBeanFactory().getBean(requiredType);
}
UserService
改造测试相关的类
package com.linnine.spring.bean.service;
@Getter
@Setter
@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 + " }";
}
}
userDao那边自己加个@Component 注解
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.linnine.spring.beans.factory.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:token.properties"/>
</bean>
<context:component-scan base-package="com.linnine.spring.bean"/>
</beans>
开始测试
@Test
public void test_scan15(){
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml");
IUserService userService = applicationContext.getBean("userService", IUserService.class);
System.out.println("测试结果:" + userService.queryUserInfo());
}