1.静态代理
首先,写一个要实现的目标的接口:
/**
* @author wayleung
* @description
* @date 2020-08-12 09:42:20
*/
public interface TargetInterface {
String sayHello(String name);
}
然后再写一个目标实现类,也就是需要被代理(增强)的类:
/**
* @author wayleung
* @description
* @date 2020-08-12 09:43:39
*/
public class Target implements TargetInterface {
@Override
public String sayHello(String name) {
String result = "Hello," + name;
System.out.println(result);
return result;
}
}
然后就是代理类的编写,此处的核心是把被代理类进行注入并调用
/**
* @author wayleung
* @description
* @date 2020-08-12 09:44:47
*/
public class Proxy implements TargetInterface {
private TargetInterface targetInterface;
public Proxy(TargetInterface targetInterface) {
this.targetInterface = targetInterface;
}
@Override
public String sayHello(String name) {
System.out.println("代理前做点东西");
String result = targetInterface.sayHello(name);
System.out.println("代理后做点东西");
return result;
}
}
最后就是使用了:
/**
* @author wayleung
* @description
* @date 2020-08-12 09:41:39
*/
public class StaticProxyDemo {
public static void main(String[] args) {
TargetInterface target = new Target();
Proxy proxy = new Proxy(target);
proxy.sayHello("way");
}
}
静态代理容易实现,容易理解,但是缺点就是每需要增强一个类就需要一个代理类,修改增加方法,代理类也需要改变,耦合严重
2.Jdk动态代理
静态代理是编译时便进行了代理,而动态代理则是通过动态修改字节码,并载入JVM来实现
Proxy和Target、TargetInterface可以共用上面的代码,我就不重复了
Jdk动态代理主要就是用了Java 反射包下的Proxy.newInstance这个方法,而这个方法里的参数又需要一个InvocationHandler的实现类,所以首先实现InvocationHandler接口:
/**
* @author wayleung
* @description
* @date 2020-08-12 10:10:27
*/
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("代理前做点东西");
Object result = method.invoke(target, args);
System.out.println("代理后做点东西");
return result;
}
}
然后就是使用了:
/**
* @author wayleung
* @description
* @date 2020-08-12 09:53:07
*/
public class DynamicProxyDemo {
public static void main(String[] args) {
TargetInterface target = new Target();
MyInvocationHandler dynamicProxyInvocationHandler = new MyInvocationHandler(target);
TargetInterface proxy = (TargetInterface) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), dynamicProxyInvocationHandler);
System.out.println(proxy.getClass().getName());
proxy.sayHello("way");
}
}
Jdk代理需要被代理类(也就是Target)实现接口(也就是TargetInterface),为什么呢?通过上面的输出可以看到 com.sun.proxy.$Proxy0 ,proxy是一个代理对象,通过反编译源码可以得知$Proxy0类继承了Proxy类,那么由于单继承的缘故,proxy要建立与代理类的关系的话那么只能通过接口了。而这也是Jdk动态代理的一个缺点,因为有时被代理类并非全都有实现接口。
3.Cglib动态代理
首先,引入相关依赖:
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
这次,为了对比,我们建一个没有实现接口的被代理类:
/**
* @author wayleung
* @description
* @date 2020-08-12 09:43:39
*/
public class TargetNoInterface{
public String sayHello(String name) {
String result = "Hello," + name;
System.out.println(result);
return result;
}
}
然后就是类似Jdk动态代理的实现相关api:
/**
* @author wayleung
* @description
* @date 2020-08-12 10:38:32
*/
public class MyMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object target, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("代理前做点东西");
Object result = methodProxy.invokeSuper(target, args);
System.out.println("代理后做点东西");
return result;
}
}
最后就是去使用它:
/**
* @author wayleung
* @description
* @date 2020-08-12 10:37:19
*/
public class CglibDynamicProxyDemo {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setClassLoader(TargetNoInterface.class.getClassLoader());
enhancer.setSuperclass(TargetNoInterface.class);
enhancer.setCallback(new MyMethodInterceptor());
TargetNoInterface proxy = (TargetNoInterface) enhancer.create();
System.out.println(proxy.getClass().getName());
proxy.sayHello("way");
}
}
通过这个可见,CGlib动态代理不需要被代理类实现接口,值得注意的是,CGlib 动态代理是通过生成一个被代理类的子类(继承)来拦截被代理类的方法调用,因此不能代理声明为 final 类型的类和方法,假如被代理类是final类,那么运行时报错:
假如被代理方法是final方法,那么能运行,但是方法没有被代理(没有被增强):