手撸spring15: @Autowired自动注入bean 以及@Value自动注入属性

上回书我们就说到要用@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());
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值