zoukankan      html  css  js  c++  java
  • springAOP自定义注解讲解

    注解:

    可以看作是对 一个 类/方法 的一个扩展的模版,每个 类/方法 按照注解类中的规则,来

    为 类/方法 注解不同的参数,在用到的地方可以得到不同的 类/方法 中注解的各种参数

    与值。

    注解的原理:

    注解本质是一个继承了Annotation的特殊接口,其具体实现类是Java运行时生成的动

    态代理类。而我们通过反射获取注解时,返回的是Java运行时生成的动态代理对象

    $Proxy1。通过代理对象调用自定义注解(接口)的方法,会最终调用

    AnnotationInvocationHandler的invoke方法。该方法会从memberValues这个Map中

    索引出对应的值。而memberValues的来源是Java常量池

    java.lang.annotation提供了四种元注解,专门注解其他的注解(在自定义注解的时候,

    需要使用到元注解):

    @Documented –注解是否将包含在JavaDoc中

    @Retention –什么时候使用该注解

    @Target –注解用于什么地方

    @Inherited – 是否允许子类继承该注解

    1.)@Retention– 定义该注解的生命周期

    ● RetentionPolicy.SOURCE : 在编译阶段丢弃。这些注解在编译结束之后就不再有任

    何意义,所以它们不会写入字节码。@Override, @SuppressWarnings都属于这类注

    解。

    ● RetentionPolicy.CLASS : 在类加载的时候丢弃。在字节码文件的处理中有用。注解

    默认使用这种方式

    ● RetentionPolicy.RUNTIME : 始终不会丢弃,运行期也保留该注解,因此可以使用

    反射机制读取该注解的信息。我们自定义的注解通常使用这种方式。

    2.)Target – 表示该注解用于什么地方。默认值为任何元素,表示该注解用于什么地

    方。可用的ElementType参数包括

    ● ElementType.CONSTRUCTOR:用于描述构造器

    ● ElementType.FIELD:成员变量、对象、属性(包括enum实例)

    ● ElementType.LOCAL_VARIABLE:用于描述局部变量

    ● ElementType.METHOD:用于描述方法

    ● ElementType.PACKAGE:用于描述包

    ● ElementType.PARAMETER:用于描述参数● ElementType.TYPE:用于描述类、接口(包括注解类型) 或enum声明

    3.)@Documented–一个简单的Annotations标记注解,表示是否将注解信息添加在java

    文档中。

    4.)@Inherited – 定义该注释和子类的关系

    @Inherited 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承

    的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个

    annotation将被用于该class的子类。

    自定义注解:

    自定义注解类编写的一些规则:

    1. Annotation型定义为@interface, 所有的Annotation会自动继承

    java.lang.Annotation这一接口,并且不能再去继承别的类或是接口.

    2. 参数成员只能用public或默认(default)这两个访问权修饰

    3. 参数成员只能用基本类型byte,short,char,int,long,float,double,boolean八种基本

    数据类型和String、Enum、Class、annotations等数据类型,以及这一些类型的数组.

    4. 要获取类方法和字段的注解信息,必须通过Java的反射技术来获取 Annotation对象,

    因为你除此之外没有别的获取注解对象的方法

    5. 注解也可以没有定义成员, 不过这样注解就没啥用了

    PS:自定义注解需要使用到元注解

    aop的讲解

    (1)AOP是什么?AOP与拦截器的区别?

    太抽象的不说,如果你知道Struts2的拦截器,拦截器就是应用的AOP的思想,它用于拦截

    Action以进行一些预处理或结果处理。而Spring的AOP是一种更通用的模式,可以拦截

    Spring管理的Bean,功能更强大,适用范围也更广,它是通过动态代理与反射机制实现的。

    ( 更 详 细 的 解 释 可 参 看 博

    客 http://blog.csdn.net/zhangliangzi/article/details/51648032 )

    (2)使用AOP需要的一些概念。

    1.通知(Advice)

    通知定义了在切入点代码执行时间点附近需要做的工作。

    Spring支持五种类型的通知:

    Before(前) org.apringframework.aop.MethodBeforeAdvice

    after(后)

    After-returning(返回后) org.springframework.aop.AfterReturningAdvice

    After-throwing(抛出后) org.springframework.aop.ThrowsAdvice

    Arround(周围) org.aopaliance.intercept.MethodInterceptorIntroduction(引入) org.springframework.aop.IntroductionInterceptor

    2.连接点(Joinpoint)

    程序能够应用通知的一个“时机”,这些“时机”就是连接点,例如方法调用时、异常

    抛出时、方法返回后等等。

    3.切入点(Pointcut)

    通知定义了切面要发生的“故事”,连接点定义了“故事”发生的时机,那么切入点就

    定义了“故事”发生的地点,例如某个类或方法的名称,Spring中允许我们方便的用正

    则表达式来指定。

    4.切面(Aspect)

    通知、连接点、切入点共同组成了切面:时间、地点和要发生的“故事”。

    5.引入(Introduction)

    引入允许我们向现有的类添加新的方法和属性(Spring提供了一个方法注入的功能)。

    6.目标(Target)

    即被通知的对象,如果没有AOP,那么通知的逻辑就要写在目标对象中,有了AOP之后它

    可以只关注自己要做的事,解耦合!

    7.代理(proxy)

    应用通知的对象,详细内容参见设计模式里面的动态代理模式。

    8.织入(Weaving)

    把切面应用到目标对象来创建新的代理对象的过程,织入一般发生在如下几个时机:

    (1)编译时:当一个类文件被编译时进行织入,这需要特殊的编译器才可以做的到,例

    如AspectJ的织入编译器;

    (2)类加载时:使用特殊的ClassLoader在目标类被加载到程序之前增强类的字节代码;

    (3)运行时:切面在运行的某个时刻被织入,SpringAOP就是以这种方式织入切面的,原

    理应该是使用了JDK的动态代理技术。

    切点表达式

    在使用spring框架配置AOP的时候,不管是通过XML配置文件还是注解的方式都需要定义

    pointcut"切入点" 例如定义切入点表达式

    expression="execution(* com.fh.service..*.*(..))"

    expression="execution(* com.fh.action.login.LoginAction.login(..))"

    execution()是最常用的切点函数,其语法如下所示: 整个表达式可以分为五个部分:

    1、execution(): 表达式主体。

    2、第一个*号:表示返回类型,*号表示所有的类型。

    3、包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,

    com.sample.service.impl包、子孙包下所有类的方法。

    4、第二个*号:表示类名,*号表示所有的类。5、*(..):最后这个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参

    数,两个句点表示任何参数。

    三、使用AOP的几种方式

    1.经典的基于代理的AOP

    2.@AspectJ注解驱动的切面

    3.纯POJO切面

    如何使用

    @AspectJ 进行注解配置

    <dependency>

    <groupId>org.aspectj</groupId>

    <artifactId>aspectjweaver</artifactId>

    <version>1.8.8</version>

    </dependency>

    1.配置

    在springMVC中增加配置

    头部文件中加入

    xmlns:aop="http://www.springframework.org/schema/aop"

    http://www.springframework.org/schema/aop

    http://www.springframework.org/schema/aop/spring-aop-4.1.xsd

    2.加入配置

    <!-- 开启注解模式 -->

    <aop:aspectj-autoproxy/>

    <!-- 扫描注解路径 -->

    <context:component-scan base-package="com.fh.aop" />

    3.定义自定义注解接口

     1 @Target({ ElementType.METHOD, ElementType.TYPE })
     2 
     3 @Retention(RetentionPolicy.RUNTIME)
     4 
     5 @Documented
     6 
     7 public @interface ILogAcpect {
     8 
     9 String methodInfo() default "";String modelName() default "";
    10 
    11 }

    4.配置注解版的AOP切面类

      1 @Aspect
      2 
      3 @Component
      4 
      5 public class LogAspect {
      6 
      7 @Pointcut("execution(* com.fh.controller..*.*(..))")
      8 
      9 private void doMethod() {
     10 
     11 }
     12 
     13 @Before("doMethod()")
     14 
     15 public void beforeAdvice(JoinPoint joinPoint) {
     16 
     17 HttpServletRequest request = ((ServletRequestAttributes)
     18 
     19 RequestContextHolder.getRequestAttributes())
     20 
     21 .getRequest();
     22 
     23 // 请求的IP
     24 
     25 String ip = request.getRemoteAddr();
     26 
     27 System.out.println(ip);
     28 
     29 try {
     30 
     31 // 当前访问的类路径
     32 
     33 String targetName =
     34 
     35 joinPoint.getTarget().getClass().getName();
     36 
     37 // 当前访问的方法名
     38 
     39 String methodName = joinPoint.getSignature().getName();
     40 
     41 // 获取当前类中的公共方法
     42 
     43 Class targetClass = Class.forName(targetName);
     44 
     45 Method[] methods = targetClass.getMethods();
     46 
     47 String params = "";
     48 
     49 if (joinPoint.getArgs() != null &&
     50 
     51 joinPoint.getArgs().length > 0) {
     52 
     53 params = Arrays.toString(joinPoint.getArgs());
     54 
     55 }
     56 
     57 Object[] arguments = joinPoint.getArgs();String logName = "";
     58 
     59 String modelName = "";
     60 
     61 for (Method method : methods) {
     62 
     63 if (method.getName().equals(methodName)) {
     64 
     65 Class[] clazzs =
     66 
     67 method.getParameterTypes();
     68 
     69 if (clazzs.length == arguments.length) {
     70 
     71 if
     72 
     73 (method.getAnnotation(ILogAcpect.class) != null) {
     74 
     75 logName =
     76 
     77 method.getAnnotation(ILogAcpect.class).methodInfo();
     78 
     79 modelName =
     80 
     81 method.getAnnotation(ILogAcpect.class).modelName();
     82 
     83 }
     84 
     85 break;
     86 
     87 }
     88 
     89 }
     90 
     91 }
     92 
     93 // 通过类路径获取所有的方法
     94 
     95 System.out.println("日志输出的明细为:" + logName);
     96 
     97 System.out.println("日志输出访问模块:" + modelName);
     98 
     99 System.out.println("访问参数:" + params);
    100 
    101 System.out.println("访问的类路径:" + targetName);
    102 
    103 System.out.println("访问的方法名:" + methodName);
    104 
    105 } catch (ClassNotFoundException e) {
    106 
    107 // TODO Auto-generated catch block
    108 
    109 e.printStackTrace();
    110 
    111 }
    112 
    113 }
    114 
    115 @After("doMethod()")
    116 
    117 public void afterAdvice() {
    118 
    119 System.out.println("afterAdvice");
    120 
    121 }@AfterThrowing(pointcut = "doMethod()", throwing = "e")
    122 
    123 public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
    124 
    125 System.err.println("异常通知:" + e.getMessage());
    126 
    127 }
    128 
    129 }
  • 相关阅读:
    windows安装python2.7后的注册(registry)问题
    用python解析pdf中的文本与表格【pdfplumber的安装与使用】
    python pdfplumber用于pdf表格提取
    python xlsxwriter写excel并操作各种格式属性
    ShellExecute, WinExec, CreateProcess区别
    Python调用Windows外部程序
    pynput使用简单说明
    有关/proc/uptime这个文件里两个参数所代表的意义
    Beyond Compare 4 提示错误“这个授权密钥已被吊销”的解决办法
    Android: adb push apk 到 system/app 目录时报“remote Read-only file system”
  • 原文地址:https://www.cnblogs.com/ycq-qiang/p/11161952.html
Copyright © 2011-2022 走看看