一、代理概念:Proxy代理模式是一种结构型设计模式,其目的就是为其他对象提供一个代理以控制对该对象的访问。代理类和委托类有共同的父类或接口,这样在任何使用委托类对象的地方动可以用代理对象替代。代理类负责请求的预处理、过滤、将请求分派给委托类处理、以及委托类执行完后的后续处理。
二、静态代理
由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。
静态类的优点:业务类只需要关注业务逻辑本身,保证了业务类的重用性。这是代理的共同有点。
静态代理缺点:1、代理类和委托类实现了相同的接口,代理类通过委托类实现了相同的方法。这样就出现了大量的代码重复。如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。2、代理对象只服务于一种类型的对象,如果要服务多类型的对象。势必要为每一种对象都进行代理,静态代理在程序规模稍大时就无法胜任了。
package proxy;
/**
* 代理接口,用于定义要执行的任务
* @author 21409262
*
*/
public interface Subject {
/**
* 需要执行的任务
*/
public void task(String taskName);
}
package proxy;
/**
* 真正执行任务的类,实现了代理接口的方法
* @author 21409262
*
*/
public class RealSubject implements Subject {
@Override
public void task(String taskName) {
// TODO Auto-generated method stub
System.out.println("正在执行任务: "+taskName);
}
}
package proxy;
/**
* 静态代理类,实现了了代理接口
* @author 21409262
*
*/
public class StaticProxySubject implements Subject {
/**
* 代理类持有一个委托类的对象引用
*/
private Subject delegate;
public StaticProxySubject(Subject delegate){
this.delegate = delegate;
}
/**
* 代理类先执行预处理命令,再将请求执行的任务分派给委托类,委托类执行完任务后,再做后续处理
*/
@Override
public void task(String taskName) {
// TODO Auto-generated method stub
System.out.println("执行任务前,预处理...");
//调用委托类执行任务
delegate.task(taskName);
System.out.println("执行任务后,后续处理...");
}
}
三、动态代理:动态代理类的字节码在程序运行时有Java反射机制动态生成,无需成员编写他的源代码。
优点:动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展行,因为Java反射机制可以生成任意类型的动态代理类对象。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。
缺点:JDK的动态代理依靠接口实现,如果有些累没有实现接口,则不能使用JDK代理,这就要使用CGLib的动态代理了。
package proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* Jdk 自带的动态代理
*/
public class JavaDynamicProxySubject implements InvocationHandler {
//代理类持有个一委托类对象
private Object target;
//绑定关系,也就是关联到哪个接口(与具体的实现类绑定)的哪些方法将被调用时,执行invoke方法。
public Object newProxyInstance(Object target){
this.target=target;
//该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
//第一个参数指定产生代理对象的类加载器,需要将其指定为和目标对象同一个类加载器
//第二个参数要实现和委托类对象一样的接口,所以只需要拿到委托类对象的实现接口
//第三个参数表明这些被拦截的方法在被拦截时需要执行哪个InvocationHandler的invoke方法
//根据传入的委托类对象返回一个代理对象
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),this);
}
//关联的这个实现类的方法被调用时将被执行
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object ret=null;
try{
/*原对象方法调用前处理日志信息*/
System.out.println("执行任务之前的预处理...");
//调用目标方法
ret=method.invoke(target, args);
/*原对象方法调用后处理日志信息*/
System.out.println("执行任务之后的后续处理...");
}catch(Exception e){
System.out.println("执行任务时出现异常...");
throw e;
}
return ret;
}
}
CGLIB代理:CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。JDK动态代理与CGLib动态代理均是实现Spring AOP的基础。
缺点:GLib创建的动态代理对象性能比JDK创建的动态代理对象的性能高不少,但是CGLib在创建代理对象时所花费的时间却比JDK多得多,所以对于单例的对象,因为无需频繁创建对象,用CGLib合适,反之,使用JDK方式要更为合适一些。同时,由于CGLib由于是采用动态创建子类的方法,对于final方法,无法进行代理。
</pre><pre name="code" class="html"><pre name="code" class="html"><span style="font-size:18px;">package proxy;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class CGLibDynamicProxySubject implements MethodInterceptor {
private Object target;
/**
* 创建代理对象
*
* @param target
* @return
*/
public Object getInstance(Object target) {
this.target = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.target.getClass());
// 回调方法
enhancer.setCallback(this);
// 创建代理对象
return enhancer.create();
}
/**
* intercept()方法拦截所有目标类方法的调用,
* obj表示目标类的实例,
* method为目标类方法的反射对象,
* args为方法的动态入参,
* proxy为代理类实例。
* proxy.invokeSuper(obj, args)通过代理类调用父类中的方法。
*/
@Override
public Object intercept(Object obj, Method method, Object[] arg,
MethodProxy proxy) throws Throwable {
// TODO Auto-generated method stub
System.out.println("执行任务前,预处理...");
proxy.invokeSuper(obj, arg);
System.out.println("执行任务后,后续处理...");
return null;
}
}
</span>
<span style="font-size:18px;">
</span>
<span style="font-size:18px;">
</span>
package proxy;
public class TestProxy {
public static void main(String[] args) {
//定义委托类对象
Subject subject = new RealSubject();
//将委托类对象做为参数传入代理类,创建代理类对象
/* Subject proxy = new StaticProxySubject(subject);
//代理类对象执行委托类对象的任务
proxy.task("拯救A股");*/
CGLibDynamicProxySubject cglib=new CGLibDynamicProxySubject();
//根据代理类获得具体的代理对象
RealSubject subject1=(RealSubject)cglib.getInstance(subject);
subject1.task("拯救A股");
}
}