AspectJ
- 定义了切面表达式的语法和解析机制
- 提供了强大的织入工具
它是通过织入的方式:直接将切面在【编译时、后】或【JVM加载的时候】进行织入到.class代码中。百度相关示例
Spring AOP
目前 Spring AOP 一共有三种配置方式
- Spring 1.2 基于接口的配置:最早的 Spring AOP 是完全基于几个接口的,MethodBeforeAdvice,AfterReturningAdvice,MethodInterceptor 等。
- Spring 2.0 schema-based 配置:Spring 2.0 以后使用 XML 的方式来配置,使用 命名空间
- Spring 2.0 @AspectJ 配置:使用注解的方式来配置,这种方式最方便
注意: AspectJ 是 AOP 的实现,但不是 Spring AOP 的实现
使用如下的 Calculate 计算类来演示
package com.mrathena.aop.usage;
public interface Calculate {
int add(int a, int b);
int subtract(int a, int b);
int multiply(int a, int b);
int divide(int a, int b);
}
package com.mrathena.aop.usage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CalculateImpl implements Calculate {
private static final Logger log = LoggerFactory.getLogger(CalculateImpl.class);
@Override
public int add(int a, int b) {
log.info("CalculateImpl.add");
return a + b;
}
@Override
public int subtract(int a, int b) {
log.info("CalculateImpl.subtract");
return a - b;
}
@Override
public int multiply(int a, int b) {
log.info("CalculateImpl.multiply");
return a * b;
}
@Override
public int divide(int a, int b) {
log.info("CalculateImpl.divide");
return a / b;
}
}
基于接口
public class CalculateMethodBeforeAdvice implements MethodBeforeAdvice {
private static final Logger log = LoggerFactory.getLogger(CalculateMethodBeforeAdvice.class);
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
log.info("{} - CalculateMethodBeforeAdvice.before", getClass());
}
}
public class CalculateAfterReturningAdvice implements AfterReturningAdvice {
private static final Logger log = LoggerFactory.getLogger(CalculateAfterReturningAdvice.class);
@Override
public void afterReturning(Object returnValue, Method method, Object target) throws Throwable {
log.info("{} - CalculateAfterReturningAdvice.afterReturning", getClass());
}
}
/**
* Interceptor 也是一个 Advice
* interface MethodInterceptor extends Interceptor
* interface Interceptor extends Advice
*/
public class CalculateMethodInterceptor implements MethodInterceptor {
private static final Logger log = LoggerFactory.getLogger(CalculateMethodInterceptor.class);
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Object result;
try {
log.info("CalculateMethodInterceptor.invoke.before");
result = invocation.proceed();
log.info("CalculateMethodInterceptor.invoke.afterReturning");
return result;
} catch (Throwable cause) {
log.info("CalculateMethodInterceptor.invoke.afterThrowing");
throw new RuntimeException(cause);
} finally {
log.info("CalculateMethodInterceptor.invoke.after");
}
}
}
Advice 方式
指定某个 Bean 的所有方法都使用指定的某些 Advice 做增强
@Configuration
public class Application {
@Bean
public Calculate calculate() {
return new CalculateImpl();
}
@Bean
public CalculateMethodBeforeAdvice calculateMethodBeforeAdvice() {
return new CalculateMethodBeforeAdvice();
}
@Bean
public CalculateAfterReturningAdvice calculateAfterReturningAdvice() {
return new CalculateAfterReturningAdvice();
}
@Bean
public Proxyfactorybean calculateProxy() {
// 需要通过 Proxyfactorybean 来生产 代理 Calculate
Proxyfactorybean factorybean = new Proxyfactorybean();
// 设置拦截链名字(有先后顺序),可以是 advice,也可以是 interceptor(本质上也是 advice),也可以是 advisor
factorybean.setInterceptorNames("calculateMethodBeforeAdvice", "calculateAfterReturningAdvice");
factorybean.setTarget(calculate());
return factorybean;
}
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Application.class);
Calculate bean = context.getBean("calculateProxy", Calculate.class);
System.out.println();
bean.add(1, 2);
System.out.println();
bean.divide(1, 0);
}
}
16:33:06.937 [main] INFO com.mrathena.aop.usage.基于接口.CalculateMethodBeforeAdvice - CalculateMethodBeforeAdvice.before
16:33:06.937 [main] INFO com.mrathena.aop.usage.CalculateImpl - CalculateImpl.add
16:33:06.937 [main] INFO com.mrathena.aop.usage.基于接口.CalculateAfterReturningAdvice - CalculateAfterReturningAdvice.afterReturning
16:33:06.938 [main] INFO com.mrathena.aop.usage.基于接口.CalculateMethodBeforeAdvice - CalculateMethodBeforeAdvice.before
16:33:06.938 [main] INFO com.mrathena.aop.usage.CalculateImpl - CalculateImpl.divide
Exception in thread "main" java.lang.ArithmeticException: / by zero
@Configuration
public class Application {
@Bean
public Calculate calculate() {
return new CalculateImpl();
}
@Bean
public CalculateMethodInterceptor calculateMethodInterceptor() {
return new CalculateMethodInterceptor();
}
@Bean
public Proxyfactorybean calculateProxy() {
// 需要通过 Proxyfactorybean 来生产 代理 Calculate
Proxyfactorybean factorybean = new Proxyfactorybean();
// 设置拦截链名字(有先后顺序),也可以是 advisor
factorybean.setInterceptorNames("calculateMethodInterceptor");
factorybean.setTarget(calculate());
return factorybean;
}
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Application.class);
Calculate bean = context.getBean("calculateProxy", 0);
}
}
16:36:33.083 [main] INFO com.mrathena.aop.usage.基于接口.CalculateMethodInterceptor - CalculateMethodInterceptor.invoke.before
16:36:33.083 [main] INFO com.mrathena.aop.usage.CalculateImpl - CalculateImpl.add
16:36:33.083 [main] INFO com.mrathena.aop.usage.基于接口.CalculateMethodInterceptor - CalculateMethodInterceptor.invoke.afterReturning
16:36:33.083 [main] INFO com.mrathena.aop.usage.基于接口.CalculateMethodInterceptor - CalculateMethodInterceptor.invoke.after
16:36:33.084 [main] INFO com.mrathena.aop.usage.基于接口.CalculateMethodInterceptor - CalculateMethodInterceptor.invoke.before
16:36:33.084 [main] INFO com.mrathena.aop.usage.CalculateImpl - CalculateImpl.divide
16:36:33.084 [main] INFO com.mrathena.aop.usage.基于接口.CalculateMethodInterceptor - CalculateMethodInterceptor.invoke.afterThrowing
16:36:33.084 [main] INFO com.mrathena.aop.usage.基于接口.CalculateMethodInterceptor - CalculateMethodInterceptor.invoke.after
Exception in thread "main" java.lang.RuntimeException: java.lang.ArithmeticException: / by zero
Advisor 方式
Advice: 指定某个 Bean 的所有方法都使用指定的某些 Advice 做增强
Advisor: 扩展了 Advice. 指定某个 Bean 的 指定某些方法,使用指定的某些 Advice 做增强
@Configuration
public class Application {
@Bean
public Calculate calculate() {
return new CalculateImpl();
}
@Bean
public CalculateMethodBeforeAdvice calculateMethodBeforeAdvice() {
return new CalculateMethodBeforeAdvice();
}
@Bean
public NameMatchMethodpointcutAdvisor calculateNameMatchMethodpointcutAdvisor() {
NameMatchMethodpointcutAdvisor advisor = new NameMatchMethodpointcutAdvisor();
// 通知(Advice) :是我们的通知类
// 通知者(Advisor):是经过包装后的细粒度控制方式。
// Advisor 持有 Advice 和 某个 pointcut
advisor.setAdvice(calculateMethodBeforeAdvice());
advisor.setMappednames("add", "subtract");
return advisor;
}
@Bean
public Proxyfactorybean calculateProxy() {
Proxyfactorybean factorybean = new Proxyfactorybean();
// 设置拦截链名字(有先后顺序),也可以是 advisor
factorybean.setInterceptorNames("calculateNameMatchMethodpointcutAdvisor");
factorybean.setTarget(calculate());
return factorybean;
}
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Application.class);
Calculate bean = context.getBean("calculateProxy", 2);
System.out.println();
bean.subtract(1, 2);
System.out.println();
bean.multiply(1, 0);
}
}
16:39:04.690 [main] INFO com.mrathena.aop.usage.基于接口.CalculateMethodBeforeAdvice - CalculateMethodBeforeAdvice.before
16:39:04.690 [main] INFO com.mrathena.aop.usage.CalculateImpl - CalculateImpl.add
16:39:04.694 [main] INFO com.mrathena.aop.usage.基于接口.CalculateMethodBeforeAdvice - CalculateMethodBeforeAdvice.before
16:39:04.695 [main] INFO com.mrathena.aop.usage.CalculateImpl - CalculateImpl.subtract
16:39:04.695 [main] INFO com.mrathena.aop.usage.CalculateImpl - CalculateImpl.multiply
16:39:04.695 [main] INFO com.mrathena.aop.usage.CalculateImpl - CalculateImpl.divide
Exception in thread "main" java.lang.ArithmeticException: / by zero
AutoproxyCreator 方式
Advice: 指定某个 Bean 的所有方法都使用指定的某些 Advice 做增强
Advisor: 扩展了 Advice. 指定某个 Bean 的 指定某些方法,使用指定的某些 Advice 做增强
AutoproxyCreator: 扩展了 Advisor. 指定某些 Bean 的 某些方法,使用指定的某些 Advice 做增强
@Configuration
public class Application {
@Bean
public Calculate calculate() {
return new CalculateImpl();
}
@Bean
public CalculateMethodBeforeAdvice calculateMethodBeforeAdvice() {
return new CalculateMethodBeforeAdvice();
}
@Bean
public NameMatchMethodpointcutAdvisor calculateNameMatchMethodpointcutAdvisor() {
NameMatchMethodpointcutAdvisor advisor = new NameMatchMethodpointcutAdvisor();
// 通知(Advice) :是我们的通知类
// 通知者(Advisor):是经过包装后的细粒度控制方式。
// advisor 持有 advice 和 某个 pointcut
// advisor 负责决定拦截哪些方法,advice 定义拦截后的逻辑
advisor.setAdvice(calculateMethodBeforeAdvice());
advisor.setMappednames("add", "subtract");
return advisor;
}
@Bean
public RegexpMethodpointcutAdvisor calculateRegexpMethodpointcutAdvisor() {
RegexpMethodpointcutAdvisor regexpMethodpointcutAdvisor = new RegexpMethodpointcutAdvisor();
regexpMethodpointcutAdvisor.setAdvice(calculateMethodBeforeAdvice());
regexpMethodpointcutAdvisor.setPatterns("com.mrathena.aop.usage.CalculateImpl.add", "com.mrathena.aop.usage.CalculateImpl.subtract");
return regexpMethodpointcutAdvisor;
}
/**
* BeanNameAutoproxyCreator 和 DefaultAdvisorAutoproxyCreator 二者选一个留下
* 需要指定 BeanNames 和 InterceptorNames(advice,interceptor,advisor)
*/
@Bean
public BeanNameAutoproxyCreator calculateBeanNameAutoproxyCreator() {
BeanNameAutoproxyCreator beanNameAutoproxyCreator = new BeanNameAutoproxyCreator();
// 设置要创建代理的那些Bean的名字
beanNameAutoproxyCreator.setBeanNames("calc*");
// 设置拦截链名字(有先后顺序),也可以是 advisor
// 拦截器使用 advice,作用于所有方法
beanNameAutoproxyCreator.setInterceptorNames("calculateMethodBeforeAdvice");
// 拦截器使用 advisor,作用于指定方法
beanNameAutoproxyCreator.setInterceptorNames("calculateRegexpMethodpointcutAdvisor", "calculateNameMatchMethodpointcutAdvisor");
beanNameAutoproxyCreator.setInterceptorNames("calculateNameMatchMethodpointcutAdvisor");
beanNameAutoproxyCreator.setInterceptorNames("calculateRegexpMethodpointcutAdvisor");
return beanNameAutoproxyCreator;
}
/**
* BeanNameAutoproxyCreator 和 DefaultAdvisorAutoproxyCreator 二者选一个留下
* DefaultAdvisorAutoproxyCreator 让容器中的所有 advisor 都生效
*/
// @Bean
// public DefaultAdvisorAutoproxyCreator calculateDefaultAdvisorAutoproxyCreator() {
// return new DefaultAdvisorAutoproxyCreator();
// }
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Application.class);
Calculate bean = context.getBean("calculate", 0);
}
}
16:40:28.030 [main] INFO com.mrathena.aop.usage.基于接口.CalculateMethodBeforeAdvice - CalculateMethodBeforeAdvice.before
16:40:28.030 [main] INFO com.mrathena.aop.usage.CalculateImpl - CalculateImpl.add
16:40:28.030 [main] INFO com.mrathena.aop.usage.基于接口.CalculateMethodBeforeAdvice - CalculateMethodBeforeAdvice.before
16:40:28.030 [main] INFO com.mrathena.aop.usage.CalculateImpl - CalculateImpl.subtract
16:40:28.030 [main] INFO com.mrathena.aop.usage.CalculateImpl - CalculateImpl.multiply
16:40:28.031 [main] INFO com.mrathena.aop.usage.CalculateImpl - CalculateImpl.divide
Exception in thread "main" java.lang.ArithmeticException: / by zero
基于 XML
基于注解
@Aspect
public class CalculateAspect {
private static final Logger log = LoggerFactory.getLogger(CalculateAspect.class);
// Before: 方法执行前
// After: 方法执行后(不管是否异常)
// AfterReturning: 方法成功执行后
// AfterThrowing: 方法抛出异常后
// Around: 自己封装整个代理逻辑
// 可以不写切点,直接把切点表达式写在 @Before 等括号中
@pointcut("execution (* com.mrathena.aop.usage.CalculateImpl.*(..))")
public void all() {}
@pointcut("execution (* com.mrathena.aop.usage.CalculateImpl.add(..))")
public void add() {}
@pointcut("execution (* com.mrathena.aop.usage.CalculateImpl.subtract(..))")
public void subtract() {}
@pointcut("execution (* com.mrathena.aop.usage.CalculateImpl.multiply(..))")
public void multiply() {}
@pointcut("execution (* com.mrathena.aop.usage.CalculateImpl.divide(..))")
public void divide() {}
@Before("all()")
public void allBefore(JoinPoint joinPoint) {
log.info("AllBefore: {},{}", joinPoint.getSignature().getName(), Arrays.asList(joinPoint.getArgs()));
}
@After("all()")
public void allAfter(JoinPoint joinPoint) {
log.info("AllAfter");
}
@AfterReturning(value = "all()", returning = "result")
public void allAfterReturning(JoinPoint joinPoint, Object result) {
log.info("AllAfterReturning: {}", result);
}
@AfterThrowing(value = "all()", throwing = "cause")
public void allAfterThrowing(JoinPoint joinPoint, Throwable cause) {
log.info("AllAfterThrowing: {}", cause.getMessage());
}
// @Before("add()")
// ajc: circular advice precedence: can't determine precedence between two or more pieces of advice that apply to the same join point: method-execution(int com.mrathena.aop.usage.CalculateImpl.add(int,int))
// 每一个方法只能被一个@Before横切
public void addBefore(JoinPoint joinPoint) {
log.info("AddBefore: {}, Arrays.asList(joinPoint.getArgs()));
}
}
@EnableAspectJAutoproxy
@Configuration
public class Application {
@Bean
public Calculate calculate() {
return new CalculateImpl();
}
@Bean
public CalculateAspect calculateAspect() {
return new CalculateAspect();
}
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Application.class);
Calculate bean = context.getBean("calculate", 0);
}
}
16:50:49.263 [main] INFO com.mrathena.aop.usage.基于注解.CalculateAspect - AllBefore: multiply, [1, 2]
16:50:49.263 [main] INFO com.mrathena.aop.usage.CalculateImpl - CalculateImpl.multiply
16:50:49.263 [main] INFO com.mrathena.aop.usage.基于注解.CalculateAspect - AllAfter
16:50:49.263 [main] INFO com.mrathena.aop.usage.基于注解.CalculateAspect - AllAfterReturning: 2
16:50:49.263 [main] INFO com.mrathena.aop.usage.基于注解.CalculateAspect - AllBefore: divide, 0]
16:50:49.263 [main] INFO com.mrathena.aop.usage.CalculateImpl - CalculateImpl.divide
16:50:49.263 [main] INFO com.mrathena.aop.usage.基于注解.CalculateAspect - AllAfter
16:50:49.263 [main] INFO com.mrathena.aop.usage.基于注解.CalculateAspect - AllAfterThrowing: / by zero
Exception in thread "main" java.lang.ArithmeticException: / by zero
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。