Spring扫描自定义注解的实现

1.定义注解

@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Interface {
    /**
     * 别名数组
     * @return String[],默认空字符串
     */
    String[] value() default "";
}

2.扫描注解注册bean的处理

public class CustomerInterfaceRegistryPostProcessor implements PriorityOrdered, BeanDefinitionRegistryPostProcessor {
    private final static Logger LOG = LoggerFactory.getLogger(CustomerInterfaceRegistryPostProcessor.class);

    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE;
    }
    
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        if (LOG.isDebugEnabled()) {
            LOG.debug("postProcessBeanFactory");
        }
        
        //搜索被Interface注解的类。key为bean的id,value为bean的实例。
        //beanFactory.getBeansWithAnnotation返回时通过getBean方法将bean的实例化,如果bean中autowired注解的属性没有实例化就会注入null
        //Map<String, Object> map = beanFactory.getBeansWithAnnotation(Interface.class);
        String[] ary = beanFactory.getBeanNamesForAnnotation(Interface.class);
        if (ary!=null && ary.length>0) {
            for (String beanName : ary) {                
                //通过Spring的beanName获取bean的类型
                Class<?> cls = beanFactory.getType(beanName);
                if (cls.getAnnotations()!=null && cls.getAnnotations().length>0) {
                    for (Annotation annotation : cls.getAnnotations()) {
                        if (annotation instanceof Interface) {
                            Interface intfc = (Interface) annotation;
                            
                            //将全限定名注册为别名
                            this.registerAlias(beanFactory, beanName, cls.getName());
                            
                            //其他别名注册
                            for (String row : intfc.value()) {
                                this.registerAlias(beanFactory, beanName, row);
                            }
                        }
                    }
                }
            }
        }
    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        if (LOG.isDebugEnabled()) {
            LOG.debug("postProcessBeanDefinitionRegistry");
        }
    }
    
    /**
     * 为bean注册别名
     * 注意:如果别名与bean的ID冲突,放弃别名注册
     * @param factory ConfigurableListableBeanFactory
     * @param beanName bean的ID
     * @param value Interface的value
     */
    private void registerAlias(ConfigurableListableBeanFactory factory, String beanId, String value) {
        //防止别名覆盖bean的ID
        if (factory.containsBeanDefinition(value)) {
            if (LOG.isDebugEnabled()) {
                LOG.debug("[failed] because value=" + value + " is existed");
            }
            return;
        }
        else {
            if (LOG.isDebugEnabled()) {
                LOG.debug("[success] beanId=" + beanId + ", value=" + value);
            }
            factory.registerAlias(beanId, value);
        }
    }
}

3.配置spring

<?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 http://www.springframework.org/schema/context/spring-context.xsd">
	<bean class="net.zhust.spring.BondeInterfaceRegistryPostProcessor"/>
    <context:component-scan base-package="net.zhust.spring"/>
</beans>

好了,通过自定义注解集成Component,实现bean被spring发现并注册完成了。

========================

如果不想让自定义注解集成Component可以实现吗?答案是肯定可以的,就是要自定义类扫描,这部分代码我是参考MyBatis的原理实现的。

1.定义注解(去除@Component)

@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Interface {
    /**
     * 别名数组
     * @return String[],默认空字符串
     */
    String[] value() default "";
}

2.自定义类扫描

public class CustomerClassPathBeanDefinitionScanner extends ClassPathBeanDefinitionScanner {

    public CustomerClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {
        super(registry, useDefaultFilters);
    }
    
    /**
     * 扫描包路径,通过include和exclude等过滤条件,返回符合条件的bean定义
     * 由于这个方法在父类是protected,所以只能通过继承类获取结果
     * @param basePackages 需要扫描的包路径
     */
    public Set<BeanDefinitionHolder> doScan(String... basePackages) {
        return super.doScan(basePackages);
    }
}

3.扫描注解注册bean的处理

public class CustomerInterfaceRegistryPostProcessor implements PriorityOrdered, BeanDefinitionRegistryPostProcessor {
    private final static Logger LOG = LoggerFactory.getLogger(CustomerInterfaceRegistryPostProcessor.class);
    /**
     * 搜索条件:Interface注解
     */
    private String annotation;
    /**
     * 搜索条件:扫描包路径数组
     */
    private String[] basePackage;
    
    public CustomerInterfaceRegistryPostProcessor() {
        super();
        this.annotation = Interface.class.getName();
        this.basePackage = new String[] {"net.zhust.spring", "net.zhust.common"};
    }

    public CustomerInterfaceRegistryPostProcessor(String annotation, String[] basePackage) {
        super();
        this.annotation = annotation;
        this.basePackage = basePackage;
    }

    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE;
    }
    
    private Set<BeanDefinitionHolder> getBeanDefinitionHolderSet(String...basePackages) {
        Set<BeanDefinitionHolder> result = null;
        BeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
        BondeClassPathBeanDefinitionScanner scanner = new BondeClassPathBeanDefinitionScanner(registry, false);
        final String annotationType = this.annotation;
        //配置过滤条件
        TypeFilter includeFilter = new TypeFilter(){

            @Override
            public boolean match(MetadataReader arg0, MetadataReaderFactory arg1) throws IOException {
                boolean result = false;
                //拥有annotationInterface指定的注解的类(非抽象)
                if (arg0.getClassMetadata().isConcrete() && arg0.getAnnotationMetadata().hasAnnotation(annotationType)) {
                    result = true;
                }
                return result;
            }
            
        };
        scanner.addIncludeFilter(includeFilter);
        
        result = scanner.doScan(basePackages);
        return result;
    }
    
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        if (LOG.isDebugEnabled()) {
            LOG.debug("postProcessBeanFactory");
        }
        
        DefaultListableBeanFactory dlbf = (DefaultListableBeanFactory) beanFactory;
        Set<BeanDefinitionHolder> beans = this.getBeanDefinitionHolderSet(this.basePackage);
        for (BeanDefinitionHolder bdh : beans) {
            //获取bean的类型(经测试此时,bean可以操作)
            try {
                Class<?> cls = Class.forName(bdh.getBeanDefinition().getBeanClassName());
                cls.getInterfaces();
                if (cls.getAnnotations()!=null && cls.getAnnotations().length>0) {
                    for (Annotation annotation : cls.getAnnotations()) {
                        if (annotation instanceof Interface) {
                            Interface intfc = (Interface) annotation;

                            //将全限定名注册为别名
                            this.registerAlias(beanFactory, bdh.getBeanName(), cls.getName());
                            
                            //其他别名注册
                            for (String row : intfc.value()) {
                                this.registerAlias(beanFactory, bdh.getBeanName(), row);
                            }
                            
                            //如果不做registerBeanDefinition,那么bean内的注解会无效(如Autowired)
                            RootBeanDefinition rbd = new RootBeanDefinition(cls);
                            dlbf.registerBeanDefinition(bdh.getBeanName(), rbd);
                        }
                    }
                }
            }
            catch(Exception ex) {
                ex.printStackTrace();
            }
        }
    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        if (LOG.isDebugEnabled()) {
            LOG.debug("postProcessBeanDefinitionRegistry");
        }
    }
    
    /**
     * 为bean注册别名
     * 注意:如果别名与bean的ID冲突,放弃别名注册
     * @param factory ConfigurableListableBeanFactory
     * @param beanName bean的ID
     * @param value Interface的value
     */
    private void registerAlias(ConfigurableListableBeanFactory factory, String beanId, String value) {
        //防止别名覆盖bean的ID
        if (factory.containsBeanDefinition(value)) {
            if (LOG.isDebugEnabled()) {
                LOG.debug("[failed] because value=" + value + " is existed");
            }
            return;
        }
        else {
            if (LOG.isDebugEnabled()) {
                LOG.debug("[success] beanId=" + beanId + ", value=" + value);
            }
            factory.registerAlias(beanId, value);
        }
    }
}

4.配置spring

<?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 http://www.springframework.org/schema/context/spring-context.xsd">
	<bean class="net.zhust.spring.BondeInterfaceRegistryPostProcessor">
		<constructor-arg index="0" value="net.zhust.spring.annotation.Interface" />
		<constructor-arg index="1">
			<array>
				<value>net.zhust.spring</value>
				<value>net.zhust.common</value>
			</array>
		</constructor-arg>
	</bean>
	<bean class="net.zhust.spring.CustomerClassPathBeanDefinitionScanner/>
    <context:component-scan base-package="net.zhust.spring"/>
</beans>

好了,就那么简单!

转载于:https://my.oschina.net/u/131091/blog/1637898

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值