Spring AOP概述
方法调用优于方法执行 Spring目前只支持方法执行这一种类型的Joinpoint
织入
public interface EchoService {
String echo(String message);
}
public class DefaultEchoService implements EchoService {
@Override
public String echo(String message) {
return message;
}
}
jdk动态代理
public class CostInvocationHandler implements InvocationHandler {
private Object target;
public CostInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long startTime = System.currentTimeMillis();
Object result = method.invoke(target, args);
long cost = System.currentTimeMillis() - startTime;
System.out.println("cost " + cost);
return result;
}
}
public static void main(String[] args) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Object proxy = Proxy.newProxyInstance(classLoader,
new Class[]{EchoService.class},
new CostInvocationHandler(new DefaultEchoService()));
EchoService echoService = (EchoService) proxy;
// cost 0
// hello world
System.out.println(echoService.echo("hello world"));
}
cglib
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(DefaultEchoService.class);
enhancer.setInterfaces(new Class[] {EchoService.class});
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object source, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
long startTime = System.currentTimeMillis();
Object result = methodProxy.invokeSuper(source, args);
long cost = System.currentTimeMillis() - startTime;
System.out.println("cost " + cost);
return result;
}
});
EchoService echoService = (EchoService) enhancer.create();
// cost 29
// hello world
System.out.println(echoService.echo("hello world"));
}
Spring AOP一代
Pointcut
public interface Pointcut {
// 通过类过滤
ClassFilter getClassFilter();
// 通过方法过滤
MethodMatcher getMethodMatcher();
Pointcut TRUE = TruePointcut.INSTANCE;
}
public class EchoPointcut implements Pointcut {
@Override
public ClassFilter getClassFilter() {
return new ClassFilter() {
@Override
public boolean matches(Class<?> clazz) {
return EchoService.class.isAssignableFrom(clazz);
}
};
}
@Override
public MethodMatcher getMethodMatcher() {
return new MethodMatcher() {
@Override
public boolean matches(Method method, Class<?> targetClass) {
return "echo".equals(method.getName()) &&
method.getParameterTypes().length == 1 &&
Objects.equals(String.class, method.getParameterTypes()[0]);
}
@Override
public boolean isRuntime() {
return false;
}
@Override
public boolean matches(Method method, Class<?> targetClass, Object... args) {
return false;
}
};
}
}
Spring内部有很多内置的实现,一般情况下我们用内置的实现即可,不用自己定义
// 方法名为 echo 会被拦截
NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
pointcut.setMappedName("echo");
Advice
public interface SayName {
String getName();
}
public class DefaultSayName implements SayName {
@Override
public String getName() {
return "I am service";
}
}
public static void main(String[] args) {
SayName sayName = new DefaultSayName();
EchoService echoService = new DefaultEchoService();
DelegatingIntroductionInterceptor interceptor =
new DelegatingIntroductionInterceptor(sayName);
Advisor advisor = new DefaultIntroductionAdvisor(interceptor, SayName.class);
ProxyFactory proxyFactory = new ProxyFactory(echoService);
proxyFactory.addAdvisor(advisor);
// hello world
EchoService proxyService = (EchoService) proxyFactory.getProxy();
System.out.println(proxyService.echo("hello world"));
// I am service
SayName proxySayName = (SayName) proxyFactory.getProxy();
System.out.println(proxySayName.getName());
}
public static void main(String[] args) {
JdkRegexpMethodPointcut pointcut = new JdkRegexpMethodPointcut();
pointcut.setPattern(".*put.*");
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
advisor.setPointcut(pointcut);
advisor.setAdvice(new MethodBeforeAdvice() {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.printf("当前存放的key为 %s,值为 %s", args[0], args[1]);
}
});
ProxyFactory proxyFactory = new ProxyFactory(new HashMap());
proxyFactory.addAdvisor(advisor);
Map<String, String> proxyMap = (Map<String, String>) proxyFactory.getProxy();
// 当前存放的key为 a,值为 a
proxyMap.put("a", "a");
}
Advisor
织入
Spring AOP的自动动态代理
手动配置
public class ProxyConfig {
// 创建代理对象
@Bean
public EchoService echoService() {
return new DefaultEchoService();
}
// 创建advice
@Bean
public CostMethodInterceptor costInterceptor() {
return new CostMethodInterceptor();
}
// 使用pointcut和advice创建advisor
@Bean
public Advisor advisor() {
NameMatchMethodPointcutAdvisor advisor = new NameMatchMethodPointcutAdvisor();
advisor.setMappedName("echo");
advisor.setAdvice(costInterceptor());
return advisor;
}
// 创建代理对象
@Bean("echoProxy")
public ProxyFactoryBean proxyFactoryBean(EchoService echoService) {
ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
proxyFactoryBean.setTarget(echoService);
proxyFactoryBean.setInterceptorNames("advisor");
return proxyFactoryBean;
}
}
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ProxyConfig.class);
EchoService echoService = (EchoService) context.getBean("echoProxy");
// cost 0
// hello world
System.out.println(echoService.echo("hello world"));
}
自动配置
public class AutoProxyConfig {
// 创建代理对象
@Bean
public EchoService echoService() {
return new DefaultEchoService();
}
// 创建advice
@Bean
public CostMethodInterceptor costInterceptor() {
return new CostMethodInterceptor();
}
// 使用pointcut和advice创建advisor
@Bean
public Advisor advisor() {
NameMatchMethodPointcutAdvisor advisor = new NameMatchMethodPointcutAdvisor();
advisor.setMappedName("echo");
advisor.setAdvice(costInterceptor());
return advisor;
}
@Bean
public DefaultAdvisorAutoProxyCreator autoProxyCreator() {
return new DefaultAdvisorAutoProxyCreator();
}
}
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AutoProxyConfig.class);
EchoService echoService = context.getBean(EchoService.class);
// cost 0
// hello world
System.out.println(echoService.echo("hello world"));
}
Spring AOP自动动态代理的实现方式
AbstractAutoProxyCreator重写了如下2个重要的方法
postProcessBeforeInstantiation(Bean实例化前阶段执行)
postProcessAfterInitialization(Bean初始化后阶段执行)
postProcessBeforeInstantiation
当用户自定义了TargetSource的实现时,会从TargetSourc
Spring AOP二代(集成了AspectJ)
激活Aspect
注解激活:@EnableAspectJAutoProxy
XML配置:<aop:aspectj-autoproxy>
Spring AOP用AspectJExpressionPointcut桥接了Aspect的筛选能力。其实Aspect有很多种类型的切点表达式,但是Spring AOP只支持如下10种,因为Aspect支持很多种类型的JoinPoint,但是Spring AOP只支持方法执行这一种JoinPoint,所以其余的表达式就没有必要了。
切点表达式
表达式类型 | 解释 |
---|---|
execution | 匹配方法表达式,首选方式 |
within | 限定类型 |
this | 代理对象是指定类型 |
target | 目标对象是指定类型 |
args | 匹配方法中的参数 |
@target | 目标对象有指定的注解 |
@args | 方法参数所属类型上有指定注解 |
@within | |
@annotation | 有指定注解的方法 |
execution
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern)
throws-pattern?)
拦截Performance类的perform方法的切点表达式如下
放几个官方的Demo
// The execution of any public method:
execution(public * *(..))
// The execution of any method with a name that begins with set
execution(* set*(..))
// The execution of any method defined by the AccountService interface
execution(* com.xyz.service.AccountService.*(..))
// The execution of any method defined in the service package:
execution(* com.xyz.service.*.*(..))
within
this
target
args
@target
@args
@within
@annotation
参考博客
[1]https://zhuanlan.zhihu.com/p/104520344
大佬分析aop的实现
[2]https://blog.csdn.net/qq_20597727/article/details/84868035
[3]https://blog.csdn.net/qq_20597727/article/details/84800176
Spring AOP之Introduction
[4]https://www.cnblogs.com/lcngu/p/6346777.html
spring aop代理时机
[5]https://www.jianshu.com/p/ef3dc73bc3b1