接口和实现
package com.company.proxy;
public interface Fruit {
void add();
void add2();
}
package com.company.proxy;
public class FruitImpl implements Fruit {
@Override
public void add() {
System.out.println("添加水果");
}
@Override
public void add2() {
System.out.println("添加水果2");
}
}
核心类 InvocationHandler
package com.company.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("pre ......");
Object o = method.invoke(target, args);
System.out.println("after ......");
return o;
}
}
实现代理
public class FruitProxy { public static void main(String[] args) { FruitImpl fruit = new FruitImpl(); MyInvocationHandler handler = new MyInvocationHandler(fruit); Object o = Proxy.newProxyInstance(fruit.getClass().getClassLoader(), fruit.getClass().getInterfaces(), handler); Fruit f = (Fruit) o; f.add(); f.add2(); } }
内部类实现:
public class FruitProxy {
public static void main(String[] args) {
Object o = Proxy.newProxyInstance(FruitImpl.class.getClassLoader(), FruitImpl.class.getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//根据方法名代理
if (method.getName().equals("add")) {
System.out.println("pre ......");
method.invoke(new FruitImpl(), args);
System.out.println("after ......");
}else {
method.invoke(new FruitImpl(), args);
}
return null;
}
});
// Fruit f = (Fruit) o;
((Fruit) o).add();
((Fruit) o).add2();
}
}
只增强add() 方法;
利用java反射和动态代理的技术 应用十分广泛;
使用JDK动态代理有一个很大的限制,就是它要求目标类必须实现了对应方法的接口,它只能为接口创建代理实例。我们在上文测试类中的Proxy的newProxyInstance方法中可以看到,该方法第二个参数便是目标类的接口。如果该类没有实现接口,这就要靠cglib动态代理了。
CGLib采用非常底层的字节码技术,可以为一个类创建一个子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,并顺势植入横切逻辑。
CGLib动态代理能代理类和接口,但是不能代理final类,也是有一定局限性。
JDK动态代理和CGLib动态代理都是运行时增强,通过将横切代码植入代理类的方式增强。与此不同的是AspectJ,它能够在通过特殊的编译器在编译时期将横切代码植入增强,这样的增强处理在运行时候更有优势,因为JDK动态代理和CGLib动态代理每次运行都需要增强。