1.AOP概念:ASPECT、JOIN POINT和ADVICE如何理解?
a.形象理解为:ASPECT是一个Class类,而Join points具体到某个要执行的点上,相当于是一个方法,Pointcnt是一个匹配Join points的条件,advice即为@before,@Around等.
b.ASPECT->N个Join points->N个advice ,即他们的对应关系为1对N对N。
2.JAVA AOP设计模式
- 代理模式:动态代理和静态代理
public static void main(String[] args) { // class $proxy0 extend proxy implements EchoService { // $proxy0(InvocationHandler handler) { // super(handler); // } // } ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); Object proxy = Proxy.newProxyInstance(classLoader, new Class[]{EchoService.class}, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (EchoService.class.isAssignableFrom(method.getDeclaringClass())) { ProxyEchoService proxyEchoService = new ProxyEchoService(new DefaultEchoService()); return proxyEchoService.echo((String) args[0]); } return null; } }); EchoService echoService = (EchoService) proxy; echoService.echo("Hello,World"); }
- 判断模式:类、方法、注解、参数、异常...
- 拦截模式:前置、后置、返回、异常
3.AOP判断模式,如何筛选Join Point
public static void main(String[] args) {
String targetClassName = "com.huawei.spring.aop.overview.EchoService";
//获取当前线程的加载器
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
try {
Class<?> targetClass = classLoader.loadClass(targetClassName);
// 方法定义:String echo(String message);
// Spring 反射工具类
Method targetMethod = ReflectionUtils.findMethod(targetClass, "echo", String.class);
System.out.println(targetMethod);
ReflectionUtils.doWithMethods(targetClass, new ReflectionUtils.MethodCallback() {
@Override
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
System.out.println("仅抛出异常为Null的方法为:" + method);
}
}, new ReflectionUtils.MethodFilter() {
@Override
public boolean matches(Method method) {
Class[] parameterTypes = method.getParameterTypes();
Class[] exceptionTypes = method.getExceptionTypes();
return parameterTypes.length == 1
&& String.class.equals(parameterTypes[0])
&& exceptionTypes.length == 1
&& NullPointerException.class.equals(exceptionTypes[0]);
}
});
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
4.AOP拦截模式
主要通过接口实现热插拔,用户只需要关注接口里面的实现,而不需要关注业务逻辑
public static void main(String[] args) {
// 前置模式 + 后置模式
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Object proxy = Proxy.newProxyInstance(classLoader, new Class[]{EchoService.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (EchoService.class.isAssignableFrom(method.getDeclaringClass())) {
// 前置拦截器
BeforeInterceptor beforeInterceptor = new BeforeInterceptor() {
@Override
public Object before(Object proxy, Method method, Object[] args) {
return System.currentTimeMillis();
}
};
Long startTime = 0L;
Long endTime = 0L;
Object result = null;
try {
// 前置拦截
startTime = (Long) beforeInterceptor.before(proxy, method, args);
EchoService echoService = new DefaultEchoService();
result = echoService.echo((String) args[0]); // 目标对象执行
// 方法执行后置拦截器
AfterReturnInterceptor afterReturnInterceptor = new AfterReturnInterceptor() {
@Override
public Object after(Object proxy, Method method, Object[] args, Object returnResult) {
return System.currentTimeMillis();
}
};
// 执行 after
endTime = (Long) afterReturnInterceptor.after(proxy, method, args, result);
} catch (Exception e) {
// 异常拦截器(处理方法执行后)
ExceptionInterceptor interceptor = (proxy1, method1, args1, throwable) -> {
};
} finally {
// finally 后置拦截器
FinallyInterceptor interceptor = new TimeFinallyInterceptor(startTime, endTime);
Long costTime = (Long) interceptor.finalize(proxy, method, args, result);
System.out.println("echo 方法执行的实现:" + costTime + " ms.");
}
}
return null;
}
});
EchoService echoService = (EchoService) proxy;
echoService.echo("Hello,World");
}
5.CGLIB动态代理
为什么java动态代理无法满足AOP需要?
JDK只能代理接口的方法,接口实现类的其它方法不能代理。Cglib是通过继承被代理类创建的代理类,所以可以代理非接口的方法,甚至普通类没有实现接口,Cglib也是可以代理的。Cglib使用字节码提升来实现AOP,具体代码如下:
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
// 指定 super class = DefaultEchoService.class
Class<?> superClass = DefaultEchoService.class;
enhancer.setSuperclass(superClass);
// 指定拦截接口
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();
// Source -> CGLIB 子类
// 目标类 -> DefaultEchoService
// 错误使用
// Object result = method.invoke(source, args);
// 正确的方法调用
Object result = methodProxy.invokeSuper(source, args);
long costTime = System.currentTimeMillis() - startTime;
System.out.println("[CGLIB 字节码提升] echo 方法执行的实现:" + costTime + " ms.");
return result;
}
});
// 创建代理对象
EchoService echoService = (EchoService) enhancer.create();
// 输出执行结果
System.out.println(echoService.echo("Hello,World"));
}