AOP的好处:
切面编程可以把业务逻辑代码跟系统服务分离,developer只要专注于开发业务逻辑就可以了。
Spring AOP实现方式 (基于动态代理实现):
1. JDK动态代理(基于接口interface实现);
2 CGLIB动态代理(基于具体实现类,创建代理子类方式实现)
AOP的运用场景有:
事务处理,日志打印,权限认证,全局异常捕获等
1. JDK动态代理通过反射来接收代理的类,但是被代理的类必须实现接口,核心是InvocationHandler和Proxy类
@Slf4j
public class UserServiceInvocationHandler implements InvocationHandler {
private Object target;
public void setTarget(Object target) {
this.target = target;
}
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log.info("start method - {}", method.getName());
log.info("args - ");
for (Object o : args) {
log.info(o.toString());
}
Object res = method.invoke(target, args);
log.info("complete method - {}", method.getName());
return res;
}
// TODO - testing
public static void main(String[] args) {
UserServiceInvocationHandler handler = new UserServiceInvocationHandler();
handler.setTarget(new UserServiceImpl());
UserService userService = (UserService) handler.getProxy(); // JDK动态代理只能通过接口,所以这边只能强制转类型为对应的接口
userService.add(new User(UUID.randomUUID().toString(), "Weijie Chen", 36));
}
}
2. cglib动态代理的类一般是没有实现接口的类,cglib是一个代码生成类库,可以在运行时动态生成某个类的子类,所以,cglib是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用cglib来做动态代理的, 主要的CGLIB工具类有Enhancer, MethodInterceptor, MethodProxy
@Slf4j
public class CglibDynamicProxy implements MethodInterceptor {
public Object createProxy(Object target){
Enhancer enhancer=new Enhancer();
enhancer.setSuperclass(target.getClass()); // create parent class
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy proxy) throws Throwable {
log.info("before executing method - " + method.getName());
log.info("this is a tag before method executing...");
Object obj= proxy.invokeSuper(o, args);
log.info("this is a tag after method executing...");
log.info("after executing method - " + method.getName());
return obj;
}
}
@Slf4j
class CglibDynamicProxyTester {
public void test1() {
log.warn("method test1 is running.");
}
public void test2() {
log.warn("method test2 is running.");
}
// TODO - testing
public static void main(String[] args) {
// 创建代理类
CglibDynamicProxy proxy = new CglibDynamicProxy();
// 根据服务类创建被代理类的代理子类
CglibDynamicProxyTester proxyObj = (CglibDynamicProxyTester) proxy.createProxy(new CglibDynamicProxyTester());
proxyObj.test1();
log.warn("========================== this is a line ===========================");
proxyObj.test2();
}
}
console 打印:
> Task :CglibDynamicProxyTester.main()
20:34:17.087 [main] INFO com.example.interview.user.proxy.CglibDynamicProxy -- before executing method - test1
20:34:17.089 [main] INFO com.example.interview.user.proxy.CglibDynamicProxy -- this is a tag before method executing...
20:34:17.102 [main] WARN com.example.interview.user.proxy.CglibDynamicProxyTester -- method test1 is running.
20:34:17.102 [main] INFO com.example.interview.user.proxy.CglibDynamicProxy -- this is a tag after method executing...
20:34:17.102 [main] INFO com.example.interview.user.proxy.CglibDynamicProxy -- after executing method - test1
20:34:17.102 [main] WARN com.example.interview.user.proxy.CglibDynamicProxyTester -- ========================== this is a line ===========================
20:34:17.102 [main] INFO com.example.interview.user.proxy.CglibDynamicProxy -- before executing method - test2
20:34:17.102 [main] INFO com.example.interview.user.proxy.CglibDynamicProxy -- this is a tag before method executing...
20:34:17.102 [main] WARN com.example.interview.user.proxy.CglibDynamicProxyTester -- method test2 is running.
20:34:17.103 [main] INFO com.example.interview.user.proxy.CglibDynamicProxy -- this is a tag after method executing...
20:34:17.103 [main] INFO com.example.interview.user.proxy.CglibDynamicProxy -- after executing method - test2