动态代理分JDK动态代理和cglib动态代理,常见的使用是在Spring的AOP中。
- JDK动态代理: 通过接口中的方法名,在动态生成的代理类中调用业务实现类的同名方法;代理实现了接口的类 ,没有实现接口的类不能使用JDK动态代理。
- Cglib动态代理: 通过继承业务类,生成的动态代理类是业务类的子类,通过重写业务方法进行代理;不能代理final修饰的类。使用cglib代理必须引入cglib的jar包。
JDK动态代理
jdk动态代理所用到的代理类在程序调用到代理类对象时才由JVM真正创建,JVM根据传进来的 业务实现类对象 以及 方法名 ,动态地创建了一个代理类的class文件并被字节码引擎执行,然后通过该代理类对象进行方法调用。
JDK动态代理为什么要实现接口
jdk动态代理使用InvocationHandler实现时代理类要继承Proxy,在需要继承proxy类获得有关方法和InvocationHandler构造方法传参的同时,java不能同时继承两个类,想要和代理的类建立联系,只能实现一个接口。
JDK动态代理的实现(接口有实现类)
1. 创建被代理类和接口
public interface BuyService {
void buy(String name);
}
import com.uv.service.BuyService;
public class BuyServiceImpl implements BuyService{
@Override
public void buy(String name) {
System.out.println("buy " + name);
}
}
2. 创建代理类InvokeProxy,实现InvocationHandler接口
/*
* @author uv
* @date 2018/10/12 13:04
*
*/
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class InvokeProxy implements InvocationHandler{
//要代理的真实对象
private Object subject;
public InvokeProxy(Object subject) {
this.subject = subject;
}
/**
* @param proxy 所代理的那个真实对象
* @param method 要调用真实对象的某个方法的Method对象
* @param args 调用真实对象某个方法时接受的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("start method:" + method.getName());
method.invoke(subject, args);
System.out.println("end method:" + method.getName());
return null;
}
}
3. 动态代理的使用
import com.uv.proxy.InvokeProxy;
import com.uv.service.BuyService;
import com.uv.service.impl.BuyServiceImpl;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
/**
* <uv> [2018/10/12 10:50]
*/
public class Main {
public static void main(String[] args) {
//要代理的真实对象
BuyService service = new BuyServiceImpl();
InvocationHandler handler = new InvokeProxy(service);
/*
* 通过Proxy的newProxyInstance方法来创建我们的代理对象
* 第一个参数 handler.getClass().getClassLoader() ,使用handler这个类的ClassLoader对象来加载我们的代理对象
* 第二个参数 realSubject.getClass().getInterfaces(),为代理对象提供的接口是真实对象所实行的接口,表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了
* 第三个参数 handler,将这个代理对象关联到了上方的 InvocationHandler 这个对象上
*/
BuyService buyService = (BuyService)Proxy.newProxyInstance(handler.getClass().getClassLoader(), service.getClass().getInterfaces(), handler);
buyService.buy("cap");
}
}
JDK动态代理的实现(接口无实现类)
1. 创建被代理的接口
public interface SellService {
String sell(String name);
}
2. 创建代理类InvokeProxy,实现InvocationHandler接口
/*
* @author uv
* @date 2018/10/12 13:56
* 没有实现类的接口的动态代理
*/
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class InterfaceProxy implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("接口方法调用开始");
//执行方法
System.out.println("method name:" + method.getName());
System.out.println("method args:" + args[0]);
System.out.println("接口方法调用结束");
return "sell " + args[0];
}
public static <T> T newInterfaceProxy(Class<T> intf) {
ClassLoader classLoader = intf.getClassLoader();
Class<?>[] interfaces = new Class[]{intf};
InterfaceProxy proxy = new InterfaceProxy();
return (T) Proxy.newProxyInstance(classLoader, interfaces, proxy);
}
}
3. 动态代理的使用
import com.uv.proxy.InterfaceProxy;
import com.uv.service.SellService;
/**
* <uv> [2018/10/12 10:50]
*/
public class Main {
public static void main(String[] args) {
SellService sellService = InterfaceProxy.newInterfaceProxy(SellService.class);
System.out.println(sellService.sell("cap"));
}
}
Cglib动态代理
cglib是针对类来实现代理的,原理是对指定的业务类生成一个子类,并覆盖其中业务方法实现代理。因为采用的是继承,所以不能对final修饰的类进行代理。
1. 添加依赖
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.4</version>
</dependency>
2. 创建被代理类,无需实现接口(实现接口也可以,不影响)
/*
* @author uv
* @date 2018/10/12 14:37
* 没有实现任何接口的被代理类
*/
public class SayService {
public void say(String name) {
System.out.println("Hello " + name);
}
}
3. 实现 MethodInterceptor方法代理接口,创建代理类
/*
* @author uv
* @date 2018/10/12 14:36
*
*/
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class CglibProxy implements MethodInterceptor{
//业务对象,被代理
private Object subject;
//相当于JDK动态代理中的绑定
public <T> T getInstance(T subject) {
//给业务对象赋值
this.subject = subject;
//创建加强器,用来创建动态代理类
Enhancer enhancer = new Enhancer();
//为加强器指定要代理的业务类(即:为下面生成的代理类指定父类)
enhancer.setSuperclass(this.subject.getClass());
//设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦
enhancer.setCallback(this);
// 创建动态代理类对象并返回
return (T)enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("before");
//调用业务类(父类中)的方法
proxy.invokeSuper(obj, args);
System.out.println("after");
return null;
}
}
4. 动态代理的使用
import com.uv.proxy.CglibProxy;
import com.uv.service.impl.SayService;
/**
* <uv> [2018/10/12 10:50]
*/
public class Main {
public static void main(String[] args) {
//被代理的对象
SayService sayService = new SayService();
//代理类
CglibProxy cglibProxy = new CglibProxy();
SayService service = cglibProxy.getInstance(sayService);
service.say("Tom");
}
}