代理模式是经典的设计模式之一,目的是为了扩展和增强类或接口。代理模式通常分为静态代理模式和动态代理模式。
1.1 静态代理模式
静态代理模式的实现比较简单,主要的实现原来是:代理类与被代理类同时实现一个主题接口,代理类持有被代理类的引用
1、例如声明一个接口:
//声明一个公共的接口
public interface UserInterface {
public abstract void getUser();
}
2、定义真实的执行类RealUser并实现公共接口:
//真实执行类---被代理类
public class RealUser implements UserInterface{
@Override
public void getUser() {
System.out.println("真实用户角色执行");
UserServices userServices = new UserServices();
userServices.setId(1);
userServices.setName("hhhh");
userServices.getUser();
}
}
3、定义代理类UserProxy实现公共接口,并持有被代理类的实例,在执行时,调用被代理类实例的getUser( )方法:
//声明代理类
public class UserProxy implements UserInterface{
private UserInterface userInterface;
//构造方法传入UserInterface类型参数
public UserProxy(UserInterface userInterface){
this.userInterface = userInterface;
}
//实现getUser()方法,在执行方法前后进行额外操作
@Override
public void getUser() {
doBefore();
userInterface.getUser();
doAfter();
}
private void doBefore() {
System.out.println("代理类开始执行");
}
private void doAfter() {
System.out.println("代理类结束执行");
}
}
写一个测试类,打印结果:
public class SpringProxyTest {
public static void main(String[] args) {
UserInterface realUser = new RealUser();
//传入真实对象RealUser
UserProxy userProxy = new UserProxy(realUser);
userProxy.getUser();
}
}
代理类开始执行
真实用户角色执行
id:1
name:hhhh
代理类结束执行
代理类实际上时被调用了被代理类的方法。
2.1 动态代理类
1、动态代理是指在程序运行时动态创建代理类。动态代理的使用方式分两种:一种是基于接口的代理。另一种是基于类的代理。
基于接口的代理方式:通过JDK自带的反射类来生成动态代理类。
基于类的代理方式:通过字节码处理来实现类代理,如CGlib和JAVAssist。
2、基于JDK反射生成代理类的例子:定义一个接口:
//公共接口
public interface UserServiceInterface {
public void getUser();
}
定义一个真实用户角色类UserServiceImpl实现接口:
//定义真实用户角色类,并实现接口
public class UserServiceImpl implements UserServiceInterface{
//实现方法
@Override
public void getUser() {
System.out.println("zhang san");
}
}
定义一个代理类UserServiceProxy,实现InvocationHandler接口,重写方法:
//定义代理类
public class UserServiceProxy implements InvocationHandler {
private Object target;
//构造方法
public UserServiceProxy(Object target){
this.target = target;
}
//通过Proxy动态生成代理类对象
public<T> T getProxy(){
return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),this);
}
//动态执行方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("JDK before");
method.invoke(target,args);
System.out.println("JDK after");
return null;
}
}
Proxy类的设计用到代理模式的设计思想,Proxy类对象实现了代理目标的所有接口,并代替目标对象进行实际的操作。但这种替代不是一种简单的替代,这样没有任何意义,代理的目的是在目标对象方法的基础上作增强,这种增强的本质通常就是对目标对象的方法进行拦截。所以,Proxy应该包括一个方法拦截器,来指示当拦截到方法调用时作何种处理。InvocationHandler就是拦截器的接口。
Object invoke(Object proxy, Method method, Object[] args)
这三个参数:第一个: Object proxy--在其上调用方法的代理实例--也就是真实的实现类
第二个:Method method---对应于在代理实例上调用的接口方法的 Method
实例。 Method
对象的声明类将是在其中声明方法的接口,该接口可以是代理类赖以继承方法的代理接口的超接口。---也就是重写的方法
第三个:Object[] args--- 包含传入代理实例上方法调用的参数值的对象数组,如果接口方法不使用参数,则为 null
。基本类型的参数被包装在适当基本包装器类。
写一个测试类:
public class SpringProxyTest {
public static void main(String[] args) {
//通过代理类生产UserServiceInterface接口类型对象
UserServiceInterface userServiceInterface = new UserServiceProxy(new UserServiceImpl()).getProxy();
//调用getUser( )方法
userServiceInterface.getUser();
}
}
JDK before
zhang san
JDK after
根据打印结果,真实用户角色类被屏蔽了,只需要暴露接口即可执行成功,屏蔽内部实现的逻辑就是代理模式的特点。