/**
* JDK 实现的动态代理 打印日志切面类
*/
public class LogInvocationHandler implements InvocationHandler {
public static void main(String[] args) {
// 需要代理的接口,被代理类实现的多个接口都必须在这里定义
Class[] proxyInterface = new Class[] { IBusiness.class,
IBusiness2.class };
// 构建AOP的Advice,这里需要歘如业务的实例
LogInvocationHandler handler = new LogInvocationHandler(new Business());
// 生成代理类的字节码加载器
ClassLoader classLoader = LogInvocationHandler.class.getClassLoader();
// 织入器,织入代码并生成代理类
IBusiness2 proxyBusiness = (IBusiness2) Proxy.newProxyInstance(
classLoader, proxyInterface, handler);
//使用代理类的实例调用方法
proxyBusiness.doSomeThing2();
((IBusiness)proxyBusiness).doSomeThing();
}
private Object target;// 目标对象
LogInvocationHandler(Object target) {
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// 执行原有的逻辑
Object rev = method.invoke(target, args);
// 执行织入的日志,你可以控制那些方法执行切入逻辑
if (method.getName().equals("doSomeThing2")) {
System.out.println("记录日志");
}
return rev;
}
}
interface IBusiness {
public boolean doSomeThing();
}
interface IBusiness2 {
public boolean doSomeThing2();
}
class Business implements IBusiness, IBusiness2 {
public boolean doSomeThing() {
System.out.println("执行业务逻辑");
return false;
}
public boolean doSomeThing2() {
System.out.println("执行业务逻辑2");
return false;
}
}
动态代理的核心其实就是代理对象的生成,即Proxy.newProxyInstance(classLoader, proxyInterface, handler)
动态代理在运行期通过接口动态生成代理类,这为其带来了一定的灵活性,
但这个灵活性却带来了两个问题,第一代理类必须实现一个接口,
如果没实现接口会抛出一个异常。第二性能影响,因为动态代理使用反射的机制实现的,
首先反射肯定比直接调用要慢,经过测试大概每个代理类比静态代理多出10几毫秒的消耗。
其次使用反射大量生成类文件可能引起Full GC造成性能影响,
因为字节码文件加载后会存放在JVM运行时区的方法区(或者叫持久代)中,
当方法区满的时候,会引起Full GC,所以当你大量使用动态代理时,
可以将持久代设置大一些,减少Full GC次数。
CgLib 实现动态代理
/**
* Cglib是一个强大的,高性能的Code生成类库,
* 它可以在运行期间扩展Java类和实现Java接口,
* 它封装了Asm,所以使用Cglib前需要引入Asm的jar
*/
public class LogIntercept implements MethodInterceptor{
public static void main(String[] args) {
//创建一个织入器
Enhancer enhancer = new Enhancer();
//设置父类
enhancer.setSuperclass(Business.class);
//设置需要织入的逻辑
enhancer.setCallback(new LogIntercept());
//使用织入器创建子类
IBusiness2 newBusiness = (IBusiness2)enhancer.create();
newBusiness.doSomeThing2();
((IBusiness)newBusiness).doSomeThing();
}
public Object intercept(Object target, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
//执行原有逻辑,注意这里是invokeSuper
Object rev = proxy.invokeSuper(target, args);
//执行织入的日志
if (method.getName().equals("doSomeThing2")) {
System.out.println("记录日志");
}
return rev;
}
}