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>
好了,就那么简单!