代理模式
一、代理模式(为其他对象提供一种代理以便控制对这个对象的访问)
代理组成:调用者,统一的接口,真实对象,代理类
原理:
通过接口,实现这样一个过程,在调用真实对象的时候,调用者并不直接与真实对象打交道,而是通过一个代理者与真实对象通信,代理者能够负责真实对象的非业务逻辑,如日志管理、访问控制 、异常处理等,使得真实对象专注于业务逻辑的实现,不受非业务逻辑的干扰。
二、静态代理实现
自己静态定义代理类
2.1 统一接口
/**
* 统一的接口
* @author Administrator
*
*/
public interface Subject {
void request();
}
2.2 真实对象
/**
* 真实对象
* @author Administrator
*
*/
public class RealSubject implements Subject {
public void request() {
System.out.println(" RealSubject excute request");
}
}
2.3 代理对象
/**
* 代理者
* @author Administrator
*
*/
public class Proxy implements Subject {
private RealSubject realSubject;
public Proxy(RealSubject realSubject){
this.realSubject = realSubject;
}
public void request() {
//植入的前置代码
System.out.println("####before##");
try {
realSubject.request();//真实对象执行的方法
System.out.println("###after##");
} catch (Exception e) {
// TODO: handle exception
System.out.println("####exception###");
}finally{
//植入的后置逻辑
System.out.println("###finally##");
}
}
}
2.4客户端调用
/**
* 客户端
* @author Administrator
*
*/
public class Client {
public static void main(String[] args) {
Subject subject = new Proxy(new RealSubject());
subject.request();
}
}
2.5 运行结果
三、JDK实现的动态代理
3.1 动态代理
不需要自己是实现代理类,利用JDK的API,在内存中自动生成代理类,源码探索:http://blog.csdn.net/shenbug/article/details/78960639
3.2 实现的要点
基于接口
InvoctionHandler实现动态代理,由
java.lang.reflect.Proxy实现代理类的创建
3.3 接口
/**
* 统一的接口
* @author Administrator
*
*/
public interface Subject {
void request();
}
3.4真实对象
/**
* 真实对象
* @author Administrator
*
*/
public class RealSubject implements Subject {
public void request() {
System.out.println(" RealSubject excute request");
}
}
3.5动态代理
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* JDK实现动态代理
* @author Administrator
*
*/
public class JdkProxy implements InvocationHandler{
//目标对象
private Object targetobject;
public JdkProxy(Object targetobject){
this.targetobject = targetobject;
}
//绑定关系,也就是关联到哪个接口(与具体的实现类绑定)的哪些方法将被调用时,执行invoke方法。
public Object newProxyInstance(){
//该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
//第一个参数指定产生代理对象的类加载器,需要将其指定为和目标对象同一个类加载器
//第二个参数要实现和目标对象一样的接口,所以只需要拿到目标对象的实现接口
//第三个参数表明这些被拦截的方法在被拦截时需要执行哪个InvocationHandler的invoke方法
//根据传入的目标返回一个代理对象
return Proxy.newProxyInstance(targetobject.getClass().getClassLoader(),
targetobject.getClass().getInterfaces(), this);
}
/**
* @param proxy 被代理的对象
* @param method 要调用的方法
* @param args 方法调用所需要的参数
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object res = null;
try {
/*原对象方法调用前处理信息*/
System.out.println("start");
//调用目标方法
res = method.invoke(targetobject, args);
} catch (Exception e) {
e.printStackTrace();
/*原对象方法调用异常处理信息*/
System.out.println("error");
}finally{
/*原对象方法调用前处理信息*/
System.out.println("success");
}
return res;
}
}
3.6 客户端调用
public class Client1 {
public static void main(String[] args) {
//System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
JdkProxy jdkProxy = new JdkProxy(new RealSubject());
Subject subject = (Subject) jdkProxy.newProxyInstance();
subject.request();
}
}
3.7 测试
四、cglib实现动态代理
4.1 实现原理
1:生成指定类对象的子类,也就是重写类中的业务函数。 2:执行回调函数,加入intercept()函数。 3:创建这个类的子类对象。
/**
* cglib实现动态代理
* @author Administrator
*
*/
public class CglibProxy implements MethodInterceptor{
//维护目标对象
private Object target;
public CglibProxy(Object target) {
this.target = target;
}
//给目标对象创建一个代理对象
public Object getProxyInstance(){
//1.工具类
Enhancer en = new Enhancer();
//2.设置父类
en.setSuperclass(target.getClass());
//3.设置回调函数
en.setCallback(this);
//4.创建子类(代理对象)
return en.create();
}
/**
* 添加植入的代码
*/
public Object intercept(Object obj, Method arg1, Object[] arg2,
MethodProxy proxy) throws Throwable {
/*原对象方法调用前处理信息*/
System.out.println("####before####");
Object result = null;
try {
//原对象方法调用
result = proxy.invokeSuper(obj, arg2);
} catch (Exception e) {
// TODO: handle exception
/*原对象方法调用异常处理信息*/
System.out.println("#####exception#####");
}finally{
/*原对象方法调用后处理信息*/
System.out.println("#####after####");
}
return result;
}
}
4.2 客户端调用
public class Client1 {
public static void main(String[] args) {
//System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
JdkProxy jdkProxy = new JdkProxy(new RealSubject());
Subject subject = (Subject) jdkProxy.newProxyInstance();
subject.request();
}
}
4.3 测试
五、jdk代理与cglib代理的对比
1.jdk基于接口实现代理,cglib基于继承的方式实现代理
2.cglib不能代理static、final修饰的类
3.jdk只能实现代理实现接口类的方法
3.jdk只能实现代理实现接口类的方法