栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

手撸spring14: component注解扫描 自动注册bean, 以及属性注入

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

手撸spring14: component注解扫描 自动注册bean, 以及属性注入

之前主要都是通过配置文件定义spring的一些bean,以及一些属性文件, 不过后面spring升级成springboot后,很多都开始用注解开发来取代配置文件了.

所以我们也开始慢慢升级了.

第一步先来两个常见注解

@Component

只要使用了@interface就能在class中被扫描到,这个我们后面再说.

package com.linnine.spring.stereotype;


@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Component {
	//组件名
    String value() default "";
}
@Scope
package com.linnine.spring.context.annotation;



@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Scope {
	//默认单例
    String value() default "singleton";
}
ClassPathScanningCandidateComponentProvider

这个类主要用于扫描注定包目录下所有带@Component注解的类

package com.linnine.spring.context.annotation;

public class ClassPathScanningCandidateComponentProvider {

    public Set findCandidateComponents(String basePackage){
        Set candidates = new LinkedHashSet<>();
        //有用component主键的都加进去
        Set> classes = ClassUtil.scanPackageByAnnotation(basePackage, Component.class);
        for (Class aClass : classes) {
            candidates.add(new BeanDefinition(aClass));
        }

        return candidates;
    }
}
ClassPathBeanDefinitionScanner

然后开始对这些类进行处理 这里是获取所有组件类定义作用域后注册

package com.linnine.spring.context.annotation;

public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider{

    private BeanDefinitionRegistry registry;

    public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
        this.registry = registry;
    }

    
    public void doScan(String... basePackages){
        for (String basePackage : basePackages) {
            //获取带有@component注解的类
            Set candidates = findCandidateComponents(basePackage);
            for (BeanDefinition beanDefinition : candidates) {
                //解析bean的作用域
                String beanScope = resolveBeanScope(beanDefinition);
                //如果有作用域
                if (StrUtil.isNotEmpty(beanScope)){
                    beanDefinition.setScope(beanScope);
                }
                //通过bean定义获取组件名 并注册
                registry.registerBeanDefinition(determineBeanName(beanDefinition),beanDefinition);
            }
        }
    }


    
    private String resolveBeanScope(BeanDefinition beanDefinition) {
        Class beanClass = beanDefinition.getBeanClass();
        //获取这个类中的注解
        Scope scope = beanClass.getAnnotation(Scope.class);
        return null != scope ?scope.value():StrUtil.EMPTY;
    }

    private String determineBeanName(BeanDefinition beanDefinition) {
        Class beanClass = beanDefinition.getBeanClass();
        // 获取组件信息
        Component component = beanClass.getAnnotation(Component.class);
        String value = component.value();
        //判断是否有组件名
        if (StrUtil.isEmpty(value)){
            //没有就取类名 变将首字母小写
            value = StrUtil.lowerFirst(beanClass.getSimpleName());
        }
        return value;
    }
}
XmlBeanDefinitionReader

然后就是把这个扫描加入到xml的扫描过程中调用

先引入个依赖, 因为xml解析的流程也被改了


    org.dom4j
    dom4j
    2.1.3

改造里面的方法,并添加了调用

protected void doLoadBeanDefinitions(InputStream inputStream) throws ClassNotFoundException, DocumentException {
    SAXReader reader = new SAXReader();
    Document document = reader.read(inputStream);
    Element root = document.getRootElement();
    Element componentScan = root.element("component-scan");
    if (null != componentScan){
        String scanPath = componentScan.attributeValue("base-package");
        if (StrUtil.isEmpty(scanPath)){
            throw new BeansException("The value of base-package attribute can not be empty or null");
        }
        scanPackage(scanPath);
    }
    List beanList = root.elements("bean");
    for (Element bean : beanList) {
        String id = bean.attributeValue("id");
        String name = bean.attributeValue("name");
        String className = bean.attributeValue("class");
        String initMethod = bean.attributeValue("init-method");
        String destroyMethodName = bean.attributeValue("destroy-method");
        String beanScope = bean.attributeValue("scope");

        // 获取 Class,方便获取类中的名称
        Class clazz = Class.forName(className);
        // 优先级 id > name
        String beanName = StrUtil.isNotEmpty(id) ? id : name;
        if (StrUtil.isEmpty(beanName)) {
            beanName = StrUtil.lowerFirst(clazz.getSimpleName());
        }

        // 定义Bean
        BeanDefinition beanDefinition = new BeanDefinition(clazz);
        beanDefinition.setInitMethodName(initMethod);
        beanDefinition.setDestroyMethodName(destroyMethodName);

        if (StrUtil.isNotEmpty(beanScope)) {
            beanDefinition.setScope(beanScope);
        }

        List propertyList = bean.elements("property");
        // 读取属性并填充
        for (Element property : propertyList) {
            // 解析标签:property
            String attrName = property.attributeValue("name");
            String attrValue = property.attributeValue("value");
            String attrRef = property.attributeValue("ref");
            // 获取属性值:引入对象、值对象
            Object value = StrUtil.isNotEmpty(attrRef) ? new BeanReference(attrRef) : attrValue;
            // 创建属性信息
            PropertyValue propertyValue = new PropertyValue(attrName, value);
            beanDefinition.getPropertyValues().addPropertyValue(propertyValue);
        }
        if (getRegistry().containsBeanDefinition(beanName)) {
            throw new BeansException("Duplicate beanName[" + beanName + "] is not allowed");
        }
        // 注册 BeanDefinition
        getRegistry().registerBeanDefinition(beanName, beanDefinition);

    }
}

private void scanPackage(String scanPath) {
    String[] basePackages = StrUtil.splitToArray(scanPath, ',');
    ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(getRegistry());
    scanner.doScan(basePackages);
}
PropertyPlaceholderConfigurer

标题上的属性注入也搞一下, 后面应该是用@Value来替代

package com.linnine.spring.beans.factory;

@Data
public class PropertyPlaceholderConfigurer implements BeanFactoryPostProcessor {

    
    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;
                    String strVal = (String) value;
                    StringBuilder builder = new StringBuilder(strVal);
                    //判断 属性值 value="${value}" 是否有使用占位符
                    int startIdx = strVal.indexOf(DEFAULT_PLACEHOLDER_PREFIX);
                    int stopIdx = strVal.indexOf(DEFAULT_PLACEHOLDER_SUFFIX);
                    //如果使用了占位符
                    if (startIdx!=-1 && stopIdx !=-1 && startIdx 
UserService 

加上注解和一条属性用来测试属性注入

补充一下token的相关方法

@Override
public String toString() {
    return "UserService#token = { " + token + " }";
}
配置文件 spring-property.xml

配置上面的属性注入类




    
    
        
    

    
    	  



我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号