spring注解之AOP
AOP,spring重要特性之一,基于OOP思想,面向切面编程,可以在不破坏原代码的情况下动态的在其前后增加功能,功能与装饰者模式相似.spring在@Transanction事务和@Cacheable数据缓存都用此拦截.我们经常用其去打日志和加事务等.
要想使用注解的方式使用AOP,需要了解以下注解:
@Aspect 声明是一个切面
@After,@Before,@Around 定义建言(advice),可直接将拦截规则(切点)作为参数
@AfterReturning 在目标方法返回后调用
@AfterThrowing 在目标方法抛出异常后调用
@Pointcut 定义拦截规则
JoinPoint 连接点(当然,这个不是注解)
以下,我用两种方式使用spring的aop
注解式
自定义注解类:
package com.yczuoxin.demo.aop;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Cutpoint {
String name();
}
被注解式切的类:
package com.yczuoxin.demo.aop;
import org.springframework.stereotype.Service;
@Service
public class AnnotationDemo {
@Cutpoint(name = "注解式切面...")
public void doSomething(){
System.out.println("AnnotationDemo doSomething method");
}
}
该注解是方便找到切点.
被方法规则切的类
package com.yczuoxin.demo.aop;
import org.springframework.stereotype.Service;
@Service
public class MethodDemo {
public void doSomething(){
System.out.println("MethodDemo doSomething method");
}
}
切面类
package com.yczuoxin.demo.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
@Aspect
@Component
public class AspectDemo {
@Pointcut("@annotation(com.yczuoxin.demo.aop.Cutpoint)")
public void annotationCutPoint(){}
@Before("annotationCutPoint()")
public void before(JoinPoint joinPoint){
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
Cutpoint cutpoint = method.getAnnotation(Cutpoint.class);
System.out.println("注解式切面" + cutpoint.name());
}
@After("execution(* com.yczuoxin.demo.aop.MethodDemo.*(..))")
public void after(JoinPoint joinPoint){
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
System.out.println("方法规则切面" + method.getName());
}
}
@Pointcut的方法名是声明切点的名字,下面的建言(例如@Before)里面传入该方法的名字即代表使用的该切点.而下面@After注解的方法规则.第一个”*”表示任意返回类型(例如public),第二个”*”表示在com.yczuoxin.demo.aop.MethodDemo类下所有的方法,且“(..)“表示这个方法的入参为任意类型、数量.
切面配置类
package com.yczuoxin.demo.aop;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@EnableAspectJAutoProxy
@ComponentScan("com.yczuoxin.demo.aop")
public class AopConfig {
}
@EnableAspectAutoProxy:使用AspectJ方式自动代理注解.默认是不开启的
测试类
package com.yczuoxin.demo.aop;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class AopTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AopConfig.class);
AnnotationDemo annotationDemo = context.getBean(AnnotationDemo.class);
MethodDemo methodDemo = context.getBean(MethodDemo.class);
// 调用被注解切的方法
annotationDemo.doSomething();
// 调用被方法规则切的方法
methodDemo.doSomething();
}
}
注解式切面注解式切面...
AnnotationDemo doSomething method
MethodDemo doSomething method
方法规则切面doSomething
看结果便知道,我们的方法切入成功了.spring的AOP主要是用了代理模式,因为可以看出来,aop可以自动选择是JDK自带的代理模式还是CGlib.我们知道代理模式可以在不修改原代码的情况下,增强方法或者切入方法.所以aop是spring的重要特点之一.