上一篇我们讲了静态代理,静态代理拥有好多好处,但是带来的缺点也很烦,于是出现了动态代理。
- 动态代理和静态代理的角色是一样的
- 动态代理的代理类是动态生成的
分为两类——类基于接口动态代理和基于类的动态代理
(1)基于接口动态代理——jdk动态代理
(2)基于类的动态代理——cglib
现在javasist来动态代理(Struts2和mybatis等都可以发现这个jar包)
百度javasist发现javassist是jboss的一个子项目,其主要的优点,在于简单,而且快速。直接使用java编码的形式,而不需要了解虚拟机指令,就能动态改变类的结构,或者动态生成类。
这里我们讲jdk动态代理,了解一种就可以触类旁通
jdk动态代理——Proxy类和InvocationHandler
实现InvocationHandler接口
查看Api InvocationHandler的定义
InvocationHandler 是代理实例的调用处理程序实现的接口。
每个代理实例都具有一个关联的调用处理程序。对代理实例调用方法时,将对方法调用进行编码并将其指派到它的调用处理程序的 invoke 方法。
文字比较绕口,要看的话可以查阅API,我们还是直接看代码吧,还是通过中介找房子这个案例
Rent.java
public interface Rent {
public void rent();
}
Host.java
public class Host implements Rent{
public void rent(){
System.out.println("房屋出租");
}
}
代理
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyInvocationhandler implements InvocationHandler{
private Object target;
public void setTarget(Object target) {
this.target = target;
}
//生成代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);//最后一个参数是实现了InvocationHandler的类
}
//proxy是代理类,method代理类的调用处理程序方法的对象
@Override
public Object invoke(Object proxy, Method method, Object[] args)`这里写代码片`
throws Throwable {
Object result=method.invoke(target, args);//反射的知识。相当于rent调用方法 args是参数
return result;
}
}
Client.java
public class Client {
public static void main(String[] args) {
Host host=new Host();
ProxyInvocationhandler pi=new ProxyInvocationhandler();
pi.setTarget(host);
Rent proxy=(Rent)pi.getProxy();
proxy.rent();
}
}
以上发现代理中
private Object target;
public void setTarget(Object target) {
this.target = target;
}
其实JDK动态代理严格应该是 ,基于接口
private Rent rent;
public void setRent(Rent rent){
this.rent = rent;
}
所以是动态代理 消除了静态代理的坏处。
JDK动态代理只能针对实现了接口的类生成代理。
cglib代理是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的所有方法,所以该类或方法不能声明称final的。
如果目标对象没有实现接口,则默认会采用CGLIB代理;
如果目标对象实现了接口,可以强制使用CGLIB实现代理
AOP包括切面(aspect)、通知(advice)、连接点(joinpoint),实现方式就是通过对目标对象的代理在连接点前后加入通知,完成统一的切面操作。
通过讲解代理为下面的spring aop做准备。