在学习Java之后会遇到很多的注解,有加载JavaBean的注解:@Component,@Service,@Controller;有获取配置文件中数值的注解@Value;有获取Http请求的数据的注解,@RequestBody。通过这些注解,spring扫描这些组件,提供相关的服务。如何自定义注解,满足自己的特定服务呢?

【转】http://blog.csdn.net/mafan121/article/details/50212137

【转】http://www.jianshu.com/p/7c2948f64b1c;深入Spring:自定义注解加载和使用

【转】http://www.jianshu.com/p/9d4bd8955d1a;spring自定义注解的使用和解析

欢迎到GitHub 上下载代码

  一、了解元注解

  元注解,元:原子,组成其他注解的基础注解。java提供了4种元注解用于注解其他注解。

  1. @Target({ElementType.TYPE})//用于描述注解的使用范围,超出范围时编译失败。
  2.   取值类型(ElementType):
  3.  
  4. 1.CONSTRUCTOR:用于描述构造器
  5.  
  6. 2.FIELD:用于描述域(成员变量)
  7.  
  8. 3.LOCAL_VARIABLE:用于描述局部变量
  9.  
  10. 4.METHOD:用于描述方法
  11.  
  12. 5.PACKAGE:用于描述包
  13.  
  14. 6.PARAMETER:用于描述参数
  15.  
  16. 7.TYPE:用于描述类、接口(包括注解类型) enum声明
  17.  
  18. @Retention(RetentionPolicy.RUNTIME)//描述注解的生命周期,即注解的生效范围。
  19.   取值范围(RetentionPolicy):
  20.  
  21. 1.SOURCE:在源文件中生效,仅存在java文件中,class文件将会去除注解。
  22.  
  23. 2.CLASS:在class文件中生效,仅保留在class文件中,运行时无法获取注解。
  24.  
  25. 3.RUNTIME:在运行时生效,保留在class文件中且运行时可通过反射机制获取。
  26.  
  27. @Documented // 用于指定javac生成API时显示该注解信息。
  28. @Inherited // 标明该注解可以由子类继承,及子类可以继承父类的注解。而默认情况下,子类是不继承父类注解的。

 

  二、读取注解

  Java通过反射机制解析注解,java在java.lang.reflect包下新增了AnnotatedElement接口, AnnotatedElement是所有注解元素的父接口,所有的注解元素都可以通过某个类反射获取AnnotatedElement对象,该对象有一下4个方法来访问Annotation信息。

  1. 1)<T extends Annotation> T getAnnotation(Class<T> annotationClass)
  2.  
  3. 返回该程序元素上存在的、指定类型的注解,如果该类型注解不存在,则返回null
  4.  
  5. 2Annotation[] getAnnotations():返回该程序元素上存在的所有注解。
  6.  
  7. 3boolean isAnnotationPresent(Class<?extends Annotation> annotationClass)
  8.  
  9. 判断该程序元素上是否包含指定类型的注解,存在则返回true,否则返回false.
  10.  
  11. 4Annotation[] getDeclaredAnnotations()
  12.  
  13. 返回直接存在于此元素上的所有注释。与此接口中的其他方法不同,该方法将忽略继承的注释。(如果没有注释直接存在于此元素上,则返回长度为零的一个数组。)该方法的调用者可以随意修改返回的数组;这不会对其他调用者返回的数组产生任何影响。

 

 三、自定义JavaBean注解。

自定义注解为

  1. package mydefineComponent;
  2.  
  3. import java.lang.annotation.Documented;
  4. import java.lang.annotation.ElementType;
  5. import java.lang.annotation.Retention;
  6. import java.lang.annotation.RetentionPolicy;
  7. import java.lang.annotation.Target;
  8.  
  9. @Target({ElementType.TYPE})
  10. @Retention(RetentionPolicy.RUNTIME)
  11. @Documented
  12. public @interface MyDefineComponent {
  13.  
  14. String value() default "";
  15. }

JAVA自定义扫描器继承ClassPathScanningCandidateComponentProvider,ClassPathBeanDefinitionScanner,并在内部添加自定义的TypeFilter。

  1. package mydefineComponent;
  2.  
  3. import java.util.Set;
  4.  
  5. import org.springframework.beans.factory.support.BeanDefinitionRegistry;
  6. import org.springframework.beans.factory.support.GenericBeanDefinition;
  7. import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
  8. import org.springframework.core.type.filter.AnnotationTypeFilter;
  9. import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
  10. import org.springframework.beans.factory.config.BeanDefinitionHolder;
  11.  
  12. public final class Scanner extends ClassPathBeanDefinitionScanner {
  13.  
  14. public Scanner(BeanDefinitionRegistry registry) {
  15. super(registry);
  16. // TODO Auto-generated constructor stub
  17. }
  18.  
  19. public void registerDefaultFilters() {
  20. this.addIncludeFilter(new AnnotationTypeFilter(MyDefineComponent.class));
  21. }
  22.  
  23. public Set<BeanDefinitionHolder> doScan(String... basePackages) {
  24. Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
  25. for (BeanDefinitionHolder holder : beanDefinitions) {
  26. GenericBeanDefinition definition = (GenericBeanDefinition) holder.getBeanDefinition();
  27. definition.getPropertyValues().add("innerClassName", definition.getBeanClassName());
  28. definition.setBeanClass(FactoryBeanTest.class);
  29. }
  30. return beanDefinitions;
  31. }
  32.  
  33. public boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
  34. return super.isCandidateComponent(beanDefinition) && beanDefinition.getMetadata()
  35. .hasAnnotation(MyDefineComponent.class.getName());
  36. }
  37.  
  38. }

  

 

ApplicationContextAware是在org.springframework.context包下的一个接口,用于获取spring的上下文,就是能通过实现这个接口来获取到spring的IOC容器中的各个bean。
  1. package mydefineComponent;
  2.  
  3. import org.springframework.beans.BeansException;
  4. import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
  5. import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
  6. import org.springframework.beans.factory.support.BeanDefinitionRegistry;
  7. import org.springframework.context.ApplicationContext;
  8. import org.springframework.context.ApplicationContextAware;
  9. import org.springframework.stereotype.Component;
  10.  
  11. @Component
  12. public class BeanScannerConfigurer implements BeanFactoryPostProcessor, ApplicationContextAware{
  13.  
  14. private ApplicationContext applicationContext;
  15.  
  16. @Override
  17. public void setApplicationContext(ApplicationContext applicationContext)
  18. throws BeansException {
  19. this.applicationContext = applicationContext;
  20.  
  21. }
  22.  
  23. @Override
  24. public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
  25. throws BeansException {
  26. Scanner scanner = new Scanner((BeanDefinitionRegistry) beanFactory);
  27. scanner.setResourceLoader(this.applicationContext);
  28. scanner.scan("mydefineComponent");
  29. }
  30.  
  31. }

 

FactoryBean是Spring中比较重要的一个类。普通的JavaBean是直接使用类的实例,但是如果一个Bean继承了这个借口,就可以通过getObject()方法来自定义实例的内容,在FactoryBeanTest的getObject()就通过代理了原始类的方法,自定义类的方法。
 
  1. package mydefineComponent;
  2.  
  3. import org.springframework.beans.factory.FactoryBean;
  4. import org.springframework.beans.factory.InitializingBean;
  5. import org.springframework.cglib.core.SpringNamingPolicy;
  6. import org.springframework.cglib.proxy.Enhancer;
  7.  
  8. public class FactoryBeanTest<T> implements InitializingBean, FactoryBean<T> {
  9.  
  10. private String innerClassName;
  11.  
  12. public void setInnerClassName(String innerClassName) {
  13. this.innerClassName = innerClassName;
  14. }
  15.  
  16. @Override
  17. public void afterPropertiesSet() throws Exception {
  18. // TODO Auto-generated method stub
  19.  
  20. }
  21.  
  22. @Override
  23. public T getObject() throws Exception {
  24. Class innerClass = Class.forName(innerClassName);
  25. if (innerClass.isInterface()) {
  26. return (T) InterfaceProxy.newInstance(innerClass);
  27. } else {
  28. Enhancer enhancer = new Enhancer();
  29. enhancer.setSuperclass(innerClass);
  30. enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
  31. enhancer.setCallback(new MethodInterceptorImpl());
  32. return (T) enhancer.create();
  33. }
  34. }
  35.  
  36. @Override
  37. public Class<?> getObjectType() {
  38. try {
  39. return Class.forName(innerClassName);
  40. } catch (ClassNotFoundException e) {
  41. e.printStackTrace();
  42. }
  43. return null;
  44. }
  45.  
  46. @Override
  47. public boolean isSingleton() {
  48. // TODO Auto-generated method stub
  49. return true;
  50. }
  51.  
  52. }

  

  1. package mydefineComponent;
  2.  
  3. import java.lang.reflect.InvocationHandler;
  4. import java.lang.reflect.Method;
  5. import java.lang.reflect.Proxy;
  6.  
  7. public class InterfaceProxy implements InvocationHandler {
  8.  
  9. @Override
  10. public Object invoke(Object proxy, Method method, Object[] args)
  11. throws Throwable {
  12. System.out.println("ObjectProxy execute:" + method.getName());
  13. return method.invoke(proxy, args);
  14. }
  15.  
  16. public static <T> T newInstance(Class<T> innerInterface) {
  17. ClassLoader classLoader = innerInterface.getClassLoader();
  18. Class[] interfaces = new Class[] { innerInterface };
  19. InterfaceProxy proxy = new InterfaceProxy();
  20. return (T) Proxy.newProxyInstance(classLoader, interfaces, proxy);
  21. }
  22. }

  

  1. package mydefineComponent;
  2.  
  3. import java.lang.reflect.Method;
  4.  
  5. import org.springframework.cglib.proxy.MethodInterceptor;
  6. import org.springframework.cglib.proxy.MethodProxy;
  7.  
  8. public class MethodInterceptorImpl implements MethodInterceptor{
  9.  
  10. @Override
  11. public Object intercept(Object o, Method method, Object[] objects,
  12. MethodProxy methodProxy) throws Throwable {
  13. System.out.println("MethodInterceptorImpl:" + method.getName());
  14. return methodProxy.invokeSuper(o, objects);
  15. }
  16.  
  17. }

  

测试代码:

  1. package mydefineComponent;
  2.  
  3. @MyDefineComponent
  4. public class ScanClass1 {
  5.  
  6. public void print() {
  7. System.out.print("scanclass1");
  8. }
  9. }

  

  1. package mydefineComponent;
  2.  
  3. import org.springframework.context.annotation.AnnotationConfigApplicationContext;
  4.  
  5. public class MyDefineComponentTest {
  6.  
  7. public static void main(String[] args) {
  8. AnnotationConfigApplicationContext acc = new AnnotationConfigApplicationContext("mydefineComponent");
  9. ScanClass1 scanClass = acc.getBean(ScanClass1.class);
  10. scanClass.print();
  11. }
  12.  
  13. }

输出:

  1. MethodInterceptorImpl:print
  2. scanclass1

三、自定义的注解 ,可通过Spring快速的获取所有使用该注解的类或方法或属性,以及注解内的值。

自定义一个注解:

  1. package com.my.annotation;
  2.  
  3. import java.lang.annotation.Documented;
  4. import java.lang.annotation.ElementType;
  5. import java.lang.annotation.Retention;
  6. import java.lang.annotation.RetentionPolicy;
  7. import java.lang.annotation.Target;
  8.  
  9. @Target({ ElementType.TYPE, ElementType.METHOD }) //可以用在方法或者类上面
  10. @Retention(RetentionPolicy.RUNTIME)
  11. @Documented
  12. public @interface Fooish {
  13.  
  14. String[] tags() default { "all" };
  15. }

自定义注解的解析功能

  1. package com.my.annotation;
  2.  
  3. import java.lang.reflect.Method;
  4. import java.util.ArrayList;
  5. import java.util.Arrays;
  6. import java.util.List;
  7. import java.util.Map;
  8.  
  9. import org.springframework.beans.BeansException;
  10. import org.springframework.beans.factory.InitializingBean;
  11. import org.springframework.context.ApplicationContext;
  12. import org.springframework.context.ApplicationContextAware;
  13. import org.springframework.stereotype.Component;
  14.  
  15. @Component
  16. public class MyFooishHandler implements ApplicationContextAware, InitializingBean{
  17.  
  18. private ApplicationContext applicationContext;
  19.  
  20. private List<String> allFooish = new ArrayList<>();
  21.  
  22. @Override
  23. public void afterPropertiesSet() throws Exception {
  24. scanFooishClass();
  25. scanFooishMethod();
  26. System.out.println(allFooish);
  27.  
  28. }
  29.  
  30. /**
  31. * 查找 用 Fooish 注解的 方法
  32. */
  33. private void scanFooishMethod() throws Exception{
  34. final Map<String, Object> permissionMap = applicationContext.getBeansWithAnnotation(Fooish.class);
  35. System.out.println("this is permissionMap" + permissionMap.toString());
  36. for (final Object permissionObject : permissionMap.values()) {
  37. final Class<? extends Object> permissionClass = permissionObject.getClass();
  38. final Fooish annotation = permissionClass.getAnnotation(Fooish.class);
  39. if(annotation != null) {
  40. allFooish.addAll(Arrays.asList(annotation.tags()));
  41. }
  42. }
  43.  
  44. }
  45.  
  46. private void scanFooishClass() throws Exception{
  47. final Map<String, Object> controllerMap = applicationContext.getBeansWithAnnotation(Fooish.class);
  48. for (final Object controllerObject : controllerMap.values()) {
  49. final Class<? extends Object> controllerClass = controllerObject.getClass();
  50. for (Method method : controllerClass.getDeclaredMethods()) {
  51. Fooish fooish = method.getAnnotation(Fooish.class);
  52. if (fooish != null) {
  53. allFooish.addAll(Arrays.asList(fooish.tags()));
  54. }
  55. }
  56. }
  57.  
  58. }
  59.  
  60. @Override
  61. public void setApplicationContext(ApplicationContext applicationContext)
  62. throws BeansException {
  63. this.applicationContext = applicationContext;
  64.  
  65. }
  66.  
  67. }

测试:

 

  1. package com.my.controller;
  2.  
  3. import java.io.File;
  4. import java.io.IOException;
  5. import java.util.List;
  6.  
  7. import javax.annotation.Resource;
  8. import javax.servlet.ServletOutputStream;
  9. import javax.servlet.http.HttpServletResponse;
  10.  
  11. import org.springframework.beans.factory.annotation.Value;
  12. import org.springframework.web.bind.annotation.RequestMapping;
  13. import org.springframework.web.bind.annotation.RequestMethod;
  14. import org.springframework.web.bind.annotation.RequestParam;
  15. import org.springframework.web.bind.annotation.RestController;
  16.  
  17. import com.my.annotation.Fooish;
  18. import com.my.model.Student;
  19. import com.my.service.FirstPageService;
  20. import com.my.service.QRCodeUtil;
  21.  
  22. @RestController
  23. @Fooish(tags={"this_is_class"})
  24. public class FirstPageController {
  25.  
  26. @Value(value = "${erweima.location:D:/Workspaces/MyEclipse 2015/entrance/src/main/resources/erweima.png}")
  27. private String imgPath;
  28.  
  29. @Resource
  30. private FirstPageService firstPageService;
  31.  
  32. @RequestMapping(value = "/", method = RequestMethod.GET)
  33. @Fooish(tags={"this_is_method"})
  34. String home() {
  35. return firstPageService.getString();
  36. }
  37.  
  38. }

  

【参考博客】

1、http://blog.csdn.net/mafan121/article/details/50212137

2、http://www.jianshu.com/p/7c2948f64b1c;深入Spring:自定义注解加载和使用

3、http://www.jianshu.com/p/9d4bd8955d1a;spring自定义注解的使用和解析

Java 自定义注解与注解解析实例的更多相关文章

  1. Java自定义数据验证注解Annotation

    本文转载自:https://www.jianshu.com/p/616924cd07e6 Java注解Annotation用起来很方便,也越来越流行,由于其简单.简练且易于使用等特点,很多开发工具都提 ...

  2. Java自定义Annotation,通过反射解析Annotation

    创建一个自定义的Annotation import java.lang.annotation.*; import java.lang.reflect.Method; @Documented @Targ ...

  3. java自定义注解知识实例及SSH框架下,拦截器中无法获得java注解属性值的问题

    一.java自定义注解相关知识 注解这东西是java语言本身就带有的功能特点,于struts,hibernate,spring这三个框架无关.使用得当特别方便.基于注解的xml文件配置方式也受到人们的 ...

  4. java中注解的使用与实例 (二)

    java 注解,从名字上看是注释,解释.但功能却不仅仅是注释那么简单.注解(Annotation) 为我们在代码中添加信息提供了一种形式化的方法,是我们可以在稍后 某个时刻方便地使用这些数据(通过 解 ...

  5. 【转】java中注解的使用与实例

    原文:http://www.cnblogs.com/pepcod/archive/2013/02/20/2918719.html java 注解,从名字上看是注释,解释.但功能却不仅仅是注释那么简单. ...

  6. java自定义注解注解方法、类、属性等等【转】

    http://anole1982.iteye.com/blog/1450421 http://www.open-open.com/doc/view/51fe76de67214563b20b385320 ...

  7. Java自定义注解和运行时靠反射获取注解

    转载:http://blog.csdn.net/bao19901210/article/details/17201173/ java自定义注解 Java注解是附加在代码中的一些元信息,用于一些工具在编 ...

  8. Java自定义注解Annotation的使用

    从 jdk5开始,Java增加了对元数据的支持,也就是Annotation,Annotation其实就是对代码的一种特殊标记,这些标记可以在编译,类加载和运行时被读取,并执行相应的处理.当然刚刚说了, ...

  9. java自定义注解类

    一.前言 今天阅读帆哥代码的时候,看到了之前没有见过的新东西, 比如java自定义注解类,如何获取注解,如何反射内部类,this$0是什么意思? 于是乎,学习并整理了一下. 二.代码示例 import ...

随机推荐

  1. Spring Boot gradle 集成servlet/jsp 教程及示例

    1.build.gradle 配置 注意,加入了war插件,在依赖中加入了jstl.tomcat-embed-jasper,这样才能运行jsp页面. buildscript { ext { sprin ...

  2. c语言define和typedef区别和使用

    define完全可以理解替换,typedef代表别名.听着差不多的意思,那2者区别在哪? 先来个简单例子查看基本使用. //define和typedef区别 #define DB double //替 ...

  3. A survey of best practices for RNA-seq data analysis RNA-seq数据分析指南

    A survey of best practices for RNA-seq data analysis RNA-seq数据分析指南 内容 前言 各位同学/老师,大家好,现在由我给大家讲讲我的文献阅读 ...

  4. [原创]分享本人自己PY写的BOOST编译程序(源码)

    本程序WINDOWS专用,只做抛砖引玉,希望诸位按照各自需求自行修改,主要目的是为了让诸位编译时可以省一些组合指令的时间,只需要修改几个参数即可自动编译. 支持64位编译模式. 改进版本:http:/ ...

  5. jquery从零开始学----选择器

     (2011-01-10 21:21:28) 转载▼ 后代选择器: $("mix mix"),当然可以是多个嵌套,但后代选择器可以是深层子代,所以$("mix mix m ...

  6. 实验二《Java面向对象》实验报告

    一.程序设计中临时变量的使用 import java.util.Arrays; public class Array { public static void main(String[] args) ...

  7. OpenGL中的像素包装理解

    OpenGL中的像素包装理解 像素包装 位图和像素图很少会被紧密包装到内存中.在许多硬件平台上,考虑到性能的原因位图和像素图的每一行的数据会从特殊的字节对齐地址开始.绝大多数编译 器会自动把变量和缓冲 ...

  8. Metasploit学习指南—基础篇

    Metasploit是一款强大的渗透测试平台,其中包括了很多渗透测试利器,本文简单介绍一下Metasploit的配置和基础的使用方法,主要包括以下几个方面: Metasploit的核心 基础的配置 M ...

  9. 20145233计算机病毒实践九之IDA的使用

    20145233计算机病毒实践之IDA的使用 PSLIST导出函数做了什么 这个函数是一个export函数,所以在view中选择export 查到后,双击打开这个函数的位置 仔细看这个函数可以发现这个 ...

  10. task4: 结对编程-词频统计[修改版]

    问题描述: 读取一个文件,统计其中单词出现次数,并按从高到低的顺序显示,相同顺序的字典序排列. 思路: 基于上次的程序用正则提取出文本里的单词,然后利用字典计数(先get,为null则置1,不为nul ...