静态代理
静态代理的好处:
- 可以使目标对象的业务更加纯粹,不用去关注公共的业务。
- 在后续需要增加公共业务时,可以在代理对象中增加,而不对目标类进行修改。在项目中要尽量避免对原代码的修改,以免修改原代码后产生严重bug。
缺点:
- 一个目标类就会产生一个代理类,代码量会提高。
下面直接看代码,房客租房需要找中介,中介再找房东的例子。
租房行为接口:
//租房
public interface Rent {
void rent();
}
房东实现类 :
//房东
public class MasterHouse implements Rent {
public MasterHouse() {
}
@Override
public void rent() {
System.out.println("出租房屋....");
}
}
中介实现类:
//代理中介
public class MyProxy implements Rent{
private MasterHouse masterHouse;
public MyProxy() {
}
public MyProxy(MasterHouse masterHouse) {
this.masterHouse = masterHouse;
}
@Override
public void rent() {
masterHouse.rent();//中介联系房东租房
}
}
租客类:
//租客
public class Tenants {
public static void main(String[] args) {
MasterHouse masterHouse = new MasterHouse();
//租客找中介租房
MyProxy proxy = new MyProxy(masterHouse);
proxy.rent();
}
}
通过这样一个中间对象来调用目标对象是比较繁琐,为什么不直接调用目标对象呢?这是为了降低耦合度,也是为了以后如果对目标类有新的公共功能增加时,可以不用修改目标类,直接在代理类中实现。当项目十分庞大时,如果对原代码修改会有很大几率产生问题。
动态代理
动态代理相比于静态代理在于其对象是动态生成,不用再一个目标类对应一个代理类了,减少了代码量,使代码复用。我们需要某一个目标类的代理对象,只需要将目标对象交给动态生成代理类,让它来生成代理对象。
动态代理分为两大类:
- 基于接口:JDK提供的动态代理
- 基于类:cglib类
基于接口实现
需要知道
Proxy类:用来动态生成代理对象;
InvocationHandler接口:当在代理实例上调用方法时,方法调用将被编码并分派到其调用处理程序的invoke
方法。按照上面的例子通俗来讲就是:租客找中介(中介调用rent()方法)租房,rent()方法将交给invoke()去自动执行,在中介类中就不需要显示的去调用rent()方法。(这一切的实现都得益于反射机制实现)
动态生成代理对象类(由上面的静态代理类变为动态,将中介类替换成此类):
public class ProxyInvocationHandler implements InvocationHandler {
//被代理的对象
private Object target;
public void setTarget(Object target){
this.target = target;
}
/**生成代理对象
* 1.调用reflect包下的Proxy类
* 2.调用Proxy类的newProxyInstance()静态方法生成代理对象
*/
public Object getProxy(){
return Proxy.newProxyInstance(
this.getClass().getClassLoader(),
target.getClass().getInterfaces(),//获取被代理对象实现的所有的接口
this
);
}
/**调用目标对象的方法
* @param proxy 代理对象
* @param method 被代理对象的方法
* @param args 被代理对象 方法被调用时 传入的实参
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(target, args);//调用目标对象的方法
return result;
}
}
租客类:
public class Tenants {
public static void main(String[] args) {
MasterHouse masterHouse = new MasterHouse();//房东
/**
* 生成代理对象
* 相当于上面的MyProxy proxy = new MyProxy(masterHouse);
*/
ProxyInvocationHandler pih = new ProxyInvocationHandler();
pih.setTarget(masterHouse);//设置要代理的目标类对象
Rent proxy = (Rent) pih.getProxy();//获取代理对象
//租房
proxy.rent();
}
}