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

[email protected]注解驱动的切面

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.定义自定义注解接口

@Target({ ElementType.METHOD, ElementType.TYPE })

@Retention(RetentionPolicy.RUNTIME)

@Documented

public @interface ILogAcpect {

String methodInfo() default "";String modelName() default "";

}

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

@Aspect

@Component

public class LogAspect {

@Pointcut("execution(* com.fh.controller..*.*(..))")

private void doMethod() {

}

@Before("doMethod()")

public void beforeAdvice(JoinPoint joinPoint) {

HttpServletRequest request = ((ServletRequestAttributes)

RequestContextHolder.getRequestAttributes())

.getRequest();

// 请求的IP

String ip = request.getRemoteAddr();

System.out.println(ip);

try {

// 当前访问的类路径

String targetName =

joinPoint.getTarget().getClass().getName();

// 当前访问的方法名

String methodName = joinPoint.getSignature().getName();

// 获取当前类中的公共方法

Class targetClass = Class.forName(targetName);

Method[] methods = targetClass.getMethods();

String params = "";

if (joinPoint.getArgs() != null &&

joinPoint.getArgs().length > 0) {

params = Arrays.toString(joinPoint.getArgs());

}

Object[] arguments = joinPoint.getArgs();String logName = "";

String modelName = "";

for (Method method : methods) {

if (method.getName().equals(methodName)) {

Class[] clazzs =

method.getParameterTypes();

if (clazzs.length == arguments.length) {

if

(method.getAnnotation(ILogAcpect.class) != null) {

logName =

method.getAnnotation(ILogAcpect.class).methodInfo();

modelName =

method.getAnnotation(ILogAcpect.class).modelName();

}

break;

}

}

}

// 通过类路径获取所有的方法

System.out.println("日志输出的明细为:" + logName);

System.out.println("日志输出访问模块:" + modelName);

System.out.println("访问参数:" + params);

System.out.println("访问的类路径:" + targetName);

System.out.println("访问的方法名:" + methodName);

} catch (ClassNotFoundException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

@After("doMethod()")

public void afterAdvice() {

System.out.println("afterAdvice");

}@AfterThrowing(pointcut = "doMethod()", throwing = "e")

public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {

System.err.println("异常通知:" + e.getMessage());

}

}

原文地址:https://www.cnblogs.com/ycq-qiang/p/11161952.html

时间: 2024-10-30 07:15:16

springAOP自定义注解讲解的相关文章

自定义注解框架的那些事

一.前言 距离上次更新已过一个半月,工作太忙也不是停更的理由.我这方面做得很不好,希望大家给予监督.首先会讲解[编译期资源注入],接着是[下拉刷新注入](通过注解来实现下拉刷新功能),最后打造一款[特色的注解框架]. 大家准备好公交卡了吗,开车了 - 二.什么是注解 每位童鞋对 注解 都有自己的理解,字面上的意思就是[额外的加入],在项目当中使用的注解的框架已经越来越多,如 : retrofit ,butterknife,androidannotations - 2017年Android百大框架

springmvc之自定义注解(annotation)

参考:日志处理 三:Filter+自定义注解实现 系统日志跟踪功能 1.项目结构 2.pom.xml,添加需要依赖 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://mav

使用Spring处理自定义注解

使用Spring处理自定义注解 本文只讲思想,不讲代码. 可能的两种方法 spring schema spring aop aspect 参考1 dubbo service 包名:com.alibaba.dubbo.config 参考2 spring mvc 包名:org.springframework.web.servlet.config 可以参考这两个的实现,利用schema添加自定义注解并处理自己的注解,注册搜索模块. 源码分析 通过schema添加配置解析如: 在 spring配置文件中

自定义注解+拦截器实现权限控制

根据5.2中的讲解,当监控high priority queue的PDSP channel设定好后,那么与之对应的event就知道了(PDSP channel与event一一对应)(注意5.x讲的是中断的配置,并不是exception的配置,4.x讲的是exception) 中断event与ISR配置代码如下,目的是使event与ISR建立联系: /*Configure event*/ EventCombinerEventConfig( systemEvent,  (TEventCombiner

基于 自定义注解 和 aop 实现使用memcache 对数据库的缓存 示例

好久没更新blog了,在新公司打拼了两个月,每天都从早忙到晚,学到了很多东西,但是没有时间来更新blog了.... 下面开始讲解这次的主题 公司老大让我研究 ocs 就是阿里云的 开放缓存服务 点击打开链接 其实就是一个memcache的服务 memchech 就是用内存来存放 key -value  在一些情况下就不必频繁的访问 数据库了(其实就是个map) 如何在常用的Dao中方便的使用这个map呢,我首先想到了 aop,然后又想到了自定义注解,那么就开始干吧.... aop动态代理要使用的

跟王老师学注解(四):自定义注解

跟王老师学注解(四):自定义注解 主讲教师:王少华   QQ群号:483773664 到此,我们已经学习完了JDK提供的3种内建注解及4种元注解,下面来了解自定义注解 一.注解类型 (一)注解类型与接口:注解类型是一种接口,但它又不同于接口 1.注解类型使用关键字@interface而不是interface 1 2 public @interface TestAno { } @interface隐含继承java.lang.annotation.Annotation接口 2.注解类型的方法定义是独

(转)利用Spring AOP自定义注解解决日志和签名校验

一.需解决的问题 部分API有签名参数(signature),Passport首先对签名进行校验,校验通过才会执行实现方法. 第一种实现方式(Origin):在需要签名校验的接口里写校验的代码,例如: boolean isValid = accountService.validSignature(appid, signature, client_signature); if (!isValid) return ErrorUtil.buildError(ErrorUtil.ERR_CODE_COM

转载:自定义注解

转载:https://juejin.im/entry/577142c3a633bd006435eea4 什么是注解 先来看看Java文档中的定义 An annotation is a form of metadata, that can be added to Java source code. Classes, methods, variables, parameters and packages may be annotated. Annotations have no direct eff

利用Spring AOP自定义注解解决日志和签名校验

转载:http://www.cnblogs.com/shipengzhi/articles/2716004.html 一.需解决的问题 部分API有签名参数(signature),Passport首先对签名进行校验,校验通过才会执行实现方法. 第一种实现方式(Origin):在需要签名校验的接口里写校验的代码,例如: boolean isValid = accountService.validSignature(appid, signature, client_signature); if (!