静态代理模式
以房屋中介帮助房东实现租房为实例
在多线程的时候也讲过静态代理模式,可以将两个案例合并
所谓静态代理模式:
1、真实对象仅仅做自己的工作就行,操作更加纯粹,不用去操心一些公共的业务
2、代理对象不仅可以帮助真实的对象实现他的方法,而且还可以额外做一些拓展的工作(即不改变原有的代码的情况下,还能够拓展业务)
3、公共业务发生拓展的时候,方便集中管理
相反,静态代理模式也有弊端,就是一个真实的对象就会对应一个代理对象,这样如果真实对象过多,则会造成代码量翻倍,效率变低,则慢慢衍生出了动态代理模式。
实现方法(案例)
1、定义租房的接口
//定义租房的接口,真实对象和代理对象都要实现这个接口
public interface Rent {
//定义租房的抽象方法
public void rent();
}
2、定义真实租房的对象(房东)
public class Host implements Rent {
@Override
public void rent() {
System.out.println("房东要租房子!");
}
}
3、定义代理的对象(中介)
public class ProxyPerson implements Rent {
//运用组合的方式,便于通过代理,调用真实对象的方法,实现真正的代理
private Host host;
//有参构造在静态代理模式中很关键,因为我们创建代理对象的时候要将真实的对象传进来
public ProxyPerson(Host host) {
this.host = host;
}
public Host getHost() {
return host;
}
public void setHost(Host host) {
this.host = host;
}
//房屋中介(代理对象)帮助实现租房的方法
@Override
public void rent() {
//洽谈
talk();
//租房子
host.rent();
//签合同
Contract();
}
//中介不仅仅能帮助房东租房子,还能做一些额外的事情
public void talk(){
System.out.println("中介和客户交流");
}
//签合同
public void Contract(){
System.out.println("中介和客户签合同");
}
}
4、测试,通过中介帮助房东实现租房的方法
public class MyTest {
public static void main(String[] args) {
//测试代理模式,能否能帮助房东实现租房
ProxyPerson proxyPerson = new ProxyPerson(new Host());
proxyPerson.rent();
}
}
5、控制台
动态代理模式
了解动态代理
一、什么是动态代理
首先动态代理的类是动态生成的,不是我们直接写好的
二、动态代理的分类:
1、基于接口的:JDK动态代理(目前较为常用)
2、基于类的:cglib
3、Java字节码实现:javasist
三、学习JDK动态代理需要先了解两个类
1、InvocationHandler
是一个接口,用来调用处理程序
2、Proxy
这个类提供了创建动态代理和实例的静态方法,可以通过这个类,去获得某个方法,来创建动态代理
动态代理的使用方法
还是以租房子为例
一、创建接口
//定义租房的接口,真实对象要实现这个接口
public interface Rent {
//定义租房的抽象方法
public void rent();
}
二、创建真实对象(房东)
public class Host implements Rent {
@Override
public void rent() {
System.out.println("房东要租房子");
}
}
三、编写生成得到动态代理的类
//我们会用这个类,自动生成代理类
/*首先要实现InvocationHandler接口*/
public class ProxyInvocationHandler implements InvocationHandler {
//被代理的接口
private Rent rent;
public void setRent(Rent rent) {
this.rent = rent;
}
//生成得到代理类
/*参数讲解(以下三个参数都是写死的,会改变的就是第二个接口的反射):
* this.getClass().getClassLoader():获取类加载器
* rent.getClass().getInterfaces():类的反射对象获取类的接口,表示需要代理的接口
*this:因为第三个参数需要传递一个 InvocationHandler,但是我们当前的类就实现了这个接口,所以传一个this即可*/
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(),rent.getClass().getInterfaces(),this);
}
@Override
//处理代理实例,并返回结果
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
//动态代理的本质,就是使用反射机制来实现!
look();
//因为我们在测试的时候,将Host对象通过set方法注入到了Rent对象中,所以这里会执行Host类中的方法
Object result = method.invoke(rent, objects);
money();
return result;
}
//拓展看房子的业务
public void look(){
System.out.println("中介带着看房子");
}
//收租金
public void money(){
System.out.println("收租金");
}
}
四、测试获取动态代理类,执行接口中的方法
public class Client {
public static void main(String[] args) {
//真实角色
Host host = new Host();
//代理角色:现在没有
ProxyInvocationHandler pih = new ProxyInvocationHandler();
//设置要代理的对象,传接口的实现类
pih.setRent((Rent) host);
//动态生成代理类
Rent proxy = (Rent) pih.getProxy();
//就可以调用接口实现类中的方法,并且还可以对这个方法进行业务拓展
proxy.rent();
}
}
五、控制台
六、将生成动态代理的类抽取成公共类,将来只需要传对应的接口即可,然后所有实现这个接口的实现类(真实对象),都可以被动态代理代理,还能为这个真实对象拓展业务
//我们会用这个类,自动生成代理类
/*首先要实现InvocationHandler接口*/
public class ProxyInvocationHandler implements InvocationHandler {
//被代理的接口
private Object target;
//写一个set方法,便于使用这个类的时候可以给target传递要代理的对象
public void setRent(Object target) {
this.target = target;
}
//生成得到代理类
/*参数讲解(以下三个参数都是写死的,会改变的就是第二个接口的反射):
* this.getClass().getClassLoader():获取类加载器
* target.getClass().getInterfaces():类的反射对象获取类的接口,表示需要代理的接口
*this:因为第三个参数需要传递一个 InvocationHandler,但是我们当前的类就实现了这个接口,所以传一个this即可*/
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
@Override
//处理代理实例,并返回结果
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
//动态代理的本质,就是使用反射机制来实现!
Object result = method.invoke(target, objects);
return result;
}
}
七、再次执行测试代码
public class Client {
public static void main(String[] args) {
//真实角色
Host host = new Host();
//代理角色:现在没有
ProxyInvocationHandler pih = new ProxyInvocationHandler();
//设置要代理的对象,传接口的实现类
pih.setRent((Rent) host);
//动态生成代理类
Rent proxy = (Rent) pih.getProxy();
//就可以调用接口实现类中的方法,并且还可以对这个方法进行业务拓展
proxy.rent();
}
}
八、控制台
九、总结
整体的生成动态代理的类,里面的方法都是固定的,但是我们必须要能看得懂,写的会是最好的。当我们把他抽取成一个工具类,我们只需要给这个类里面的Object类传递一个实现类,就可以通过getProxy()方法成动态代理对象,执行其中的方法,并且还可以做一些拓展的业务。这样一来我们不需要再像静态代理模式那样一个真实对象都要写一个对应的代理类了
至此,你已经深刻的掌握了Java中如何实现动、静代理,后续会持续更新,敬请期待!