一、代理模式概念
为某个对象提供一个代理,以控制对这个对象的访问。 代理类和委托类有共同的父类或父接口,这样在任何使用委托类对象的地方都可以用代理对象替代。代理类负责请求的预处理、过滤、将请求分派给委托类处理、以及委托类执行完请求后的后续处理。
代理接口(Subject)、代理类(ProxySubject)、委托类(RealSubject)
1、代理类与委托类实现同一个业务接口,使用时直接使用代理类对象
2、代理类对象内有一个委托类的对象,在new代理类对象时需要传递一个委托类对象以便代理类调用委托类的业务方法
3、代理类是实现业务功能的增强,并没有实现业务功能的方法,在调用业务功能方法时直接调用委托类的业务方法
2、静态代理代码实现
1、业务接口
/**
* 业务接口
*/
public interface Subject {
/**
* 这里是业务逻辑方法
*/
public void dealTask();
}
2、委托类,具体处理业务
/**
* 真正执行任务的类,实现了业务接口。
*/
public class RealSubject implements Subject {
/**
* 执行业务逻辑
*/
@Override
public void dealTask() {
System.out.println("此处为业务功能");
}
}
3、代理类
/**
* 代理类,实现了业务接口。
*/
public class ProxySubject implements Subject {
//代理类持有一个委托类的对象引用
private Subject delegate;
public ProxySubject(Subject delegate) {
this.delegate = delegate;
}
/**
* 对业务进行功能增强
*/
@Override
public void dealTask() {
System.out.println("此处为业务功能的增强");
//将真正的业务给委托类处理
delegate.dealTask();
System.out.println("此处为业务功能的增强");
}
}
4、生成静态代理类工厂
public class SubjectStaticFactory {
//客户类调用此工厂方法获得代理对象。
//对客户类来说,其并不知道返回的是代理类对象还是委托类对象。
public static Subject getInstance(){
return new ProxySubject(new RealSubject());
}
}
5、客户类使用业务功能
public class Client1 {
public static void main(String[] args) {
Subject proxy = SubjectStaticFactory.getInstance();
proxy.dealTask();
}
}
缺点:
- 如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。
- 代理对象的一个接口只服务于一种类型的对象,如果要代理的方法很多,势必要为每一种方法都进行代理,静态代理在程序规模稍大时就无法胜任了。
三、JDK动态代理
动态代理
代理对象在程序运行的过程中动态在内存构建。可以灵活的进行业务功能的切换。
JDK动态代理
- 目标对象必须实现业务接口
- 代理对象不需要实现业务接口
JDK动态代理用到的类和接口
-
java.lang.reflect.Proxy类。它有一个方法Proxy.newProxyInstance(……)专门用来生成动态代理对象
public static Object newProxyInstance( ClassLoader loader, //类加载器 Class<?>[] interfaces, //目标对象实现的所有接口 InvocationHandler h //相当于静态代理中的代理类,代理的功能增强与业务功能 的调用在这 ) throws IllegalArgumentException
-
Method类
反射用的类,用来进行业务方法的方法的反射调用
method对象接住业务方法
method.invoke()方法:
正常来说,我们调用对象的方法是通过 . 运算符来进行的,这里我们介绍另一种方法,有以下几个步骤:1,获取该类的Class Type;2,通过getMethod方法获取Method对象;3,通过调用invoke方法来执行对象的某个方法
-
InvocationHandler接口
它是实现代理和业务功能的。我们在调用时使用匿名内部实现
四、JDK动态代理的代码实现
1、业务接口(与静态代理一样)
/**
* 业务接口
*/
public interface Subject {
/**
* 这里是业务逻辑方法
*/
public void dealTask();
}
2、委托类,具体处理业务(与静态代理一样)
/**
* 真正执行任务的类,实现了业务接口。
*/
public class RealSubject implements Subject {
/**
* 执行业务逻辑
*/
@Override
public void dealTask() {
System.out.println("此处为业务功能");
}
}
3、生成动态代理类工厂
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class SubjectStaticFactory {
//委托类对象
Subject delegate;
//传入委托类对象
public SubjectStaticFactory(Subject delegate){
this.delegate = delegate;
}
//返回动态代理对象
public Object getInstance(){
return Proxy.newProxyInstance(
delegate.getClass().getClassLoader(),
delegate.getClass().getInterfaces(),
//相当于静态代理中的代理类,完成代理的功能增强与业务功能的调用。使用匿名内部实现
new InvocationHandler() {
@Override
public Object invoke(
//创建代理对象
Object proxy,
//使用反射调用业务方法,此处的method可以看成业务方法(dealTask())
Method method,
//目标方法的参数
Object[] args) throws Throwable {
System.out.println("此处为业务功能的增强");
//通过反射机制得到的method对象,method就相当于业务方法dealTask()
//当出现多个业务方法时,我调用哪个业务方法,这里的method就是哪个业务方法
Object obj = method.invoke(delegate,args); //这个obj是业务方法的返回值
System.out.println("此处为业务功能的增强");
return obj; //返回业务方法的返回值
}
}
);
}
}
4、客户类使用业务功能(与静态代理几乎一样)
public class Client1 {
public static void main(String[] args) {
SubjectStaticFactory factory = new SubjectStaticFactory(new RealSubject());
Subject proxy = (Subject) factory.getInstance();
proxy.dealTask();
}
}
五、快速上手JDK动态代理
生成动态代理类工厂时只需要将以下代码按注释部分修改,其他按模板照抄即可
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class SubjectStaticFactory {
//这里传入类型为委托类的类型
Subject delegate;
//这里传入委托类
public SubjectStaticFactory(Subject delegate){
this.delegate = delegate;
}
public Object getInstance(){
return Proxy.newProxyInstance(
delegate.getClass().getClassLoader(),
delegate.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(
Object proxy,
Method method,
Object[] args) throws Throwable {
//在这里做代理的功能增强与业务功能的调用
//对业务功能增强的代码写这
//调用业务方法
Object obj = method.invoke(delegate,args);
//对业务功能增强的代码写这
return obj;
}
}
);
}
}
使用代码:
public static void main(String[] args) {
SubjectStaticFactory factory = new SubjectStaticFactory(
new RealSubject()//此处传入委托类
);
Subject proxy = (Subject) factory.getInstance();
proxy.dealTask();//此处调用业务方法
}