Spring AOP
目录
AOP是代码解耦的一种方式,将核心业务逻辑与系统级服务(日志、事务等)分离。
Spring AOP的原理是动态代理,动态代理的实现方式有三种:jdk、cglib、aspectj,Spring AOP容器会根据目标对象采取不同的动态代理实现。
动态代理
jdk动态代理
jdk动态代理要求目标类必须实现某个接口
public class ProxyTest {
public static void main(String[] args) {
SomeService service = new SomeServiceImpl();
SomeService proxy = (SomeService) Proxy.newProxyInstance(service.getClass().getClassLoader(),
service.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("proxy... "+method.toString());
return method.invoke(service, args);
}
}
);
System.out.println(proxy.doService());
}
}
interface SomeService {
int doService();
}
class SomeServiceImpl implements SomeService {
@Override
public int doService() {
System.out.println("doSrvice");
return 123;
}
@Override
public String toString() {
return "SomeServiceImpl{}";
}
}
/*
proxy...public abstract int SomeService.doService()
doSrvice
123
*/
cglib动态代理
cglib的动态代理是通过生成目标对象实现类的子类来实现的,这个子类对象就是代理对象。所以使用cglib动态代理要求目标类不能是final的。
public class CglibTest {
public static void main(String[] args) {
ServiceImpl proxy = new ServiceImplCglibProxyFactory().newProxyInstance(new ServiceImpl());
proxy.doService();
}
}
class ServiceImpl{
public void doService(){
System.out.println("doService");
}
}
class ServiceImplCglibProxyFactory implements MethodInterceptor {
ServiceImpl service;
public ServiceImpl newProxyInstance(ServiceImpl service){
this.service=service;
Enhancer enhancer=new Enhancer();
//设置父类为目标类
enhancer.setSuperclass(service.getClass());
//回调intercept方法
enhancer.setCallback(this);
return (ServiceImpl)enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("proxy...");
Object invoke = method.invoke(service, args);
return invoke;
}
}
/*
proxy...
doService
*/
AOP的几个概念
切面Aspect
分为通知、顾问,对主业务逻辑的增强。
一般作为单独的类,定义了在什么时间、什么方法完成什么样的功能
织入Weaving
将切面插入到目标对象的过程
通知Advice
定义织入的时间点,例如前置通知、后置通知、环绕通知等,不能选择切入点
顾问Advisor
将通知进行包装,在不同的时间点将切面织入不同的切入点
连接点
可以被切面织入的方法
切入点
实际被切面织入的方法
Spring框架使用AspectJ的注解
AspectJ通知的类型
- 前置@Before
- 后置@AfetrReturning:可以接收返回值,不可修改返回值
- 环绕@Around:可以修改返回值
- 异常@AfterThrowing
- 最终@After
使用: