Spring自定义注解的使用

http://blog.youkuaiyun.com/jackyechina/article/details/52980903


http://blog.youkuaiyun.com/purisuit_knowledge/article/details/55195442


http://www.tuicool.com/articles/FFvymu



二、ClassPathMapperScanner代码分析

ClassPathMapperScanner类实现了ClassPathBeanDefinitionScanner并对registerFilters方法与doScan方法进行了重写。
registerFilters方法主要是根据annotationClass或者是markerInterface属性来指定只扫描指定包下面的类带有某个注解的接口或者是为某个接口的子接口的接口。
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public void registerFilters() {  
  2.     boolean acceptAllInterfaces = true;  
  3.   
  4.     // if specified, use the given annotation and / or marker interface  
  5.     if (this.annotationClass != null) {  
  6.       addIncludeFilter(new AnnotationTypeFilter(this.annotationClass));  
  7.       acceptAllInterfaces = false;  
  8.     }  
  9.   
  10.     // override AssignableTypeFilter to ignore matches on the actual marker interface  
  11.     if (this.markerInterface != null) {  
  12.       addIncludeFilter(new AssignableTypeFilter(this.markerInterface) {  
  13.         @Override  
  14.         protected boolean matchClassName(String className) {  
  15.           return false;  
  16.         }  
  17.       });  
  18.       acceptAllInterfaces = false;  
  19.     }  
  20.   
  21.     if (acceptAllInterfaces) {  
  22.       // default include filter that accepts all classes  
  23.       addIncludeFilter(new TypeFilter() {  
  24.         public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {  
  25.           return true;  
  26.         }  
  27.       });  
  28.     }  
  29.   
  30.     // exclude package-info.java  
  31.     addExcludeFilter(new TypeFilter() {  
  32.       public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {  
  33.         String className = metadataReader.getClassMetadata().getClassName();  
  34.         return className.endsWith("package-info");  
  35.       }  
  36.     });  
  37.   }  

doScan方法用来将包下面的接口转化为MapperFactoryBean的类。
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public Set<BeanDefinitionHolder> doScan(String... basePackages) {  
  2.     Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);  
  3.   
  4.     if (beanDefinitions.isEmpty()) {  
  5.       logger.warn("No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration.");  
  6.     } else {  
  7.       for (BeanDefinitionHolder holder : beanDefinitions) {  
  8.         GenericBeanDefinition definition = (GenericBeanDefinition) holder.getBeanDefinition();  
  9.   
  10.         if (logger.isDebugEnabled()) {  
  11.           logger.debug("Creating MapperFactoryBean with name '" + holder.getBeanName()   
  12.               + "' and '" + definition.getBeanClassName() + "' mapperInterface");  
  13.         }  
  14.   
  15.         // the mapper interface is the original class of the bean  
  16.         // but, the actual class of the bean is MapperFactoryBean  
  17.         definition.getPropertyValues().add("mapperInterface", definition.getBeanClassName());  
  18.         definition.setBeanClass(MapperFactoryBean.class);  
  19.   
  20.         definition.getPropertyValues().add("addToConfig"this.addToConfig);  
  21.   
  22.         boolean explicitFactoryUsed = false;  
  23.         if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) {  
  24.           definition.getPropertyValues().add("sqlSessionFactory"new RuntimeBeanReference(this.sqlSessionFactoryBeanName));  
  25.           explicitFactoryUsed = true;  
  26.         } else if (this.sqlSessionFactory != null) {  
  27.           definition.getPropertyValues().add("sqlSessionFactory"this.sqlSessionFactory);  
  28.           explicitFactoryUsed = true;  
  29.         }  
  30.   
  31.         if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) {  
  32.           if (explicitFactoryUsed) {  
  33.             logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");  
  34.           }  
  35.           definition.getPropertyValues().add("sqlSessionTemplate"new RuntimeBeanReference(this.sqlSessionTemplateBeanName));  
  36.           explicitFactoryUsed = true;  
  37.         } else if (this.sqlSessionTemplate != null) {  
  38.           if (explicitFactoryUsed) {  
  39.             logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");  
  40.           }  
  41.           definition.getPropertyValues().add("sqlSessionTemplate"this.sqlSessionTemplate);  
  42.           explicitFactoryUsed = true;  
  43.         }  
  44.   
  45.         if (!explicitFactoryUsed) {  
  46.           if (logger.isDebugEnabled()) {  
  47.             logger.debug("Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");  
  48.           }  
  49.           definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);  
  50.         }  
  51.       }  
  52.     }  
  53.   
  54.     return beanDefinitions;  
  55.   }  

三、通过实现ClassPathBeanDefinitionScanner类自下定义bean注解的扫描

1、定义自己的注解

这里的注解并没有被@Component注解,而通过ClassPathBeanDefinitionScanner 类实现扫描。
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. @Target({ ElementType.TYPE })  
  2. @Retention(RetentionPolicy.RUNTIME)  
  3. @Documented  
  4. public @interface CustomizeComponent {  
  5.  String value() default "";  
  6. }  

2、被注解的类

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. @CustomizeComponent  
  2. public class ScanClass1 {  
  3. public void print() {  
  4.     System.out.println("scanClass1");  
  5. }  
  6. }  

3、自定义的BeanScannerConfigurer类

BeanScannerConfigurer用于嵌入到Spring的加载过程的中,这里用到了BeanFactoryPostProcessor 和 ApplicationContextAware。Spring提供了一些的接口使程序可以嵌入Spring的加载过程。这个类中的继承ApplicationContextAware接口,Spring会读取ApplicationContextAware类型的的JavaBean,并调用setApplicationContext(ApplicationContext applicationContext)传入Spring的applicationContext。
同样继承BeanFactoryPostProcessor接口,Spring会在BeanFactory的相关处理完成后调用postProcessBeanFactory方法,进行定制的功能。
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. @Component  
  2. public static class BeanScannerConfigurer implements  BeanFactoryPostProcessor, ApplicationContextAware {  
  3.     private ApplicationContext applicationContext;  
  4.       
  5.     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {  
  6.         this.applicationContext = applicationContext;  
  7.     }  
  8.     public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {  
  9.         Scanner scanner = new Scanner((BeanDefinitionRegistry) beanFactory);  
  10.         scanner.setResourceLoader(this.applicationContext);  
  11.         scanner.scan("org.wcong.test.spring.scan");  
  12.     }  
  13. }  

4、ClassPathBeanDefinitionScanner实现类Scanner

Scanner继承的ClassPathBeanDefinitionScanner是Spring内置的Bean定义的扫描器。
includeFilter里定义了类的过滤器,newAnnotationTypeFilter(CustomizeComponent.class)表示只取被CustomizeComponent修饰的类。只扫描我们自已定义的注解。
doScan里扫面了包底下的读取到BeanDefinitionHolder,自定义GenericBeanDefinition相关功能。

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public final static class Scanner extends ClassPathBeanDefinitionScanner {  
  2.       public Scanner(BeanDefinitionRegistry registry) {  
  3.           super(registry);  
  4.       }  
  5.       public void registerDefaultFilters() {  
  6.           this.addIncludeFilter(new AnnotationTypeFilter(CustomizeComponent.class));  
  7.       }  
  8.       public Set<BeanDefinitionHolder> doScan(String... basePackages) {  
  9.           Set<BeanDefinitionHolder> beanDefinitions =   super.doScan(basePackages);  
  10.           for (BeanDefinitionHolder holder : beanDefinitions) {  
  11.               GenericBeanDefinition definition = (GenericBeanDefinition) holder.getBeanDefinition();  
  12.               definition.getPropertyValues().add("innerClassName", definition.getBeanClassName());  
  13.               definition.setBeanClass(FactoryBeanTest.class);  
  14.           }  
  15.           return beanDefinitions;  
  16.       }  
  17.       public boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {  
  18.          return super.isCandidateComponent(beanDefinition) && beanDefinition.getMetadata()  
  19.     .hasAnnotation(CustomizeComponent.class.getName());  
  20.       }  
  21. }  

5、得到我们Bean

FactoryBean是Spring中比较重要的一个类。它的描述如下

Interface to be implemented by objects used within a BeanFactory which are themselves factories. 
If a bean implements this interface, it is used as a factory for an object to expose, not directly as a bean* instance that will be exposed itself
普通的JavaBean是直接使用类的实例,但是如果一个Bean继承了这个借口,就可以通过getObject()方法来自定义实例的内容,在FactoryBeanTest的getObject()就通过代理了原始类的方法,自定义类的方法。
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public static class FactoryBeanTest<T> implements InitializingBean, FactoryBean<T> {  
  2.       private String innerClassName;  
  3.       public void setInnerClassName(String innerClassName) {  
  4.           this.innerClassName = innerClassName;  
  5.       }  
  6.       public T getObject() throws Exception {  
  7.           Class innerClass = Class.forName(innerClassName);  
  8.           if (innerClass.isInterface()) {  
  9.               return (T) InterfaceProxy.newInstance(innerClass);  
  10.           } else {  
  11.               Enhancer enhancer = new Enhancer();  
  12.               enhancer.setSuperclass(innerClass);  
  13.               enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);  
  14.               enhancer.setCallback(new MethodInterceptorImpl());  
  15.               return (T) enhancer.create();  
  16.           }  
  17.       }  
  18.       public Class<?> getObjectType() {  
  19.           try {  
  20.                 return Class.forName(innerClassName);  
  21.           } catch (ClassNotFoundException e) {  
  22.                 e.printStackTrace();  
  23.           }  
  24.           return null;  
  25.       }  
  26.       public boolean isSingleton() {  
  27.           return true;  
  28.       }  
  29.       public void afterPropertiesSet() throws Exception {  
  30.       }  
  31. }  
  32. public static class InterfaceProxy implements InvocationHandler {  
  33.       public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
  34.           System.out.println("ObjectProxy execute:" + method.getName());  
  35.           return method.invoke(proxy, args);  
  36.       }  
  37.       public static <T> T newInstance(Class<T> innerInterface) {  
  38.           ClassLoader classLoader = innerInterface.getClassLoader();  
  39.           Class[] interfaces = new Class[] { innerInterface };  
  40.           InterfaceProxy proxy = new InterfaceProxy();  
  41.           return (T) Proxy.newProxyInstance(classLoader, interfaces, proxy);  
  42.       }  
  43. }  
  44. public static class MethodInterceptorImpl implements MethodInterceptor {  
  45.       public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {  
  46.           System.out.println("MethodInterceptorImpl:" + method.getName());  
  47.           return methodProxy.invokeSuper(o, objects);  
  48.       }  
  49. }  

6、main函数

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. @Configuration  
  2. public class CustomizeScanTest {  
  3.    public static void main(String[] args) {  
  4.     AnnotationConfigApplicationContext annotationConfigApplicationContext = new        AnnotationConfigApplicationContext();                  
  5.     annotationConfigApplicationContext.register(CustomizeScanTest.class);  
  6.     annotationConfigApplicationContext.refresh();  
  7.     ScanClass1 injectClass = annotationConfigApplicationContext.getBean(ScanClass1.class);  
  8.     injectClass.print();  
  9.    }  
  10. }  
详解代码见https://github.com/wcong/learn-java/blob/master/src/main/java/org/wcong/test/spring/CustomizeScanTest.java






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值