首先介绍------代理
代理:需要三个对象1:定义规则的接口;2:实现内容的主体;3代理;
其中定义规则的接口中,定义好需要完成的内容;
实现内容的主体要实际完成内容;
最重要的来了:代理中需要注入一个主体,这个主体就是实际完成的对象;代理实现内容,但不是实际执行,只是在方法中去调用主体去完成,这样就可以在完成的前后去添加或者修改内容;
举个例子:A要卖房子,B是中介。客户C去买房子。这里不管是A还是B都可以卖房子,这样就定义接口中的方法卖房子,A实现就是卖自己的房子。重点来了:B实现卖房子,但B没有房子,需要A实际去卖,这样把A登记在B中,B卖房子实际上是A去卖的。。。
C去中介B买的房子还是A的房子,然后被收取中介费,收费过程就是一个对原有过程的增强。代理过程完毕。
然后介绍------静态代理
上代码:
//接口
public interface Person {
public void give();
}
//实现类
public class Student implements Person {
public void give() {
System.out.println("缴费");
}
}
//代理类
public class StuProxy implements Person {
Person s;
public StuProxy(Person p){
this.s=p;
}
public void give() {
System.out.println("班长收费");
s.give();
}
}
//测试
public static void main(String[] args){
//创建实现类
Person stu=new Student();
//创建代理类
Person stuPro=new StuProxy(stu);
//代理实现过程
stuPro.give();
}
然后介绍------动态代理之JDK实现
介绍完代理过程了,接下来看静态代理-------就是在编码时就写好了代理的过程。
动态代理就是没有代理类,在程序运行时,去创建代理对象,并且去实现增强。
上代码:
//动态代理类
public class MyInvocationHandler<T> implements InvocationHandler {
T t;
public MyInvocationHandler(T t){
this.t=t;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理执行" +method.getName() + "方法");
//代理过程中插入监测方法,计算该方法耗时
Object result = method.invoke(t, args);
return result;
}
}
//测试类
public static void main(String[] args){
Person stu=new Student();
//创建一个与代理对象相关联的InvocationHandler
InvocationHandler stuHandler = new MyInvocationHandler<Person>(stu);
// 使用Proxy类的getProxyClass静态方法生成一个动态代理类stuProxyClass
Class<?> stuProxyClass = Proxy.getProxyClass(Person.class.getClassLoader(), new Class<?>[] {Person.class});
//获得stuProxyClass 中一个带InvocationHandler参数的构造器constructor
Constructor<?> constructor = PersonProxy.getConstructor(InvocationHandler.class);
// 通过构造器constructor来创建一个动态实例stuProxy
Person stuProxy = (Person) cons.newInstance(stuHandler);
stuProxy.give();
}
就此,一个动态代理对象就创建完毕,当然,上面四个步骤可以通过java.lang.reflect.Proxy类的newProxyInstances方法来简化:
//创建一个与代理对象相关联的InvocationHandler
InvocationHandler stuHandler = new MyInvocationHandler<Person>(stu);
//创建一个代理对象stuProxy,代理对象的每个执行方法都会替换执行Invocation中的invoke方法
Person stuProxy= (Person) Proxy.newProxyInstance(Person.class.getClassLoader(), new Class<?>[]{Person.class}, stuHandler);
查看测试类:
public static void main(String[] args) {
//被代理对象
Person s=new Student();
InvocationHandler p=new MyInvocationHandler(s);
//得到代理对象
Person stuProxy = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(),new Class<?>[]{Person.class}, p);
//代理对象调用代理的方法
stuProxy.give();
}
InvocationHandle实现动态代理局限性:必须要有同意的接口;
然后介绍------动态代理之cglib
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 CGLibProxy implements MethodInterceptor {
// CGlib需要代理的目标对象
private Object targetObject;
public Object createProxyObject(Object obj) {
this.targetObject = obj;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(obj.getClass());
enhancer.setCallback(this);
Object proxyObj = enhancer.create();
return proxyObj;
}
public Object intercept(Object proxy, Method method, Object[] args,MethodProxy methodProxy) throws Throwable {
Object obj = null;
// 过滤方法
if ("addUser".equals(method.getName())) {
checkPopedom();
}
obj =method.invoke(targetObject, args);
return obj;
}
private void checkPopedom() {
System.out.println("检查权限:checkPopedom()!");
}
}
通过CGLIB成功创建的动态代理,实际是被代理类的一个子类。那么如果被代理类被标记成final,也就无法通过CGLIB去创建动态代理。
小结
对比jdk实现与cglib实现,1.JDK代理使用的是反射机制实现aop的动态代理,CGLIB代理使用字节码处理框架asm,通过修改字节码生成子类。所以jdk动态代理的方式创建代理对象效率较高,执行效率较低,cglib创建效率较低,执行效率高;2.JDK动态代理机制是委托机制,具体说动态实现接口类,调用其他对象去实现功能,CGLIB则使用的继承机制,具体说被代理类和代理类是继承关系,所以代理类是可以赋值给被代理类的,如果被代理类有接口,那么代理类也可以赋值给接口。
从代码维护上来讲,cglib与jdk去实现的动态代理,都完成了对原有流程的增强,当原始内容改变时,比如增加一个方法,jdk需要修改接口、实现类;cglib其实只是修改实现类就好,接口没有关系;
另外还有一种实现方式,就是读取jvm中的需要代理的类的class,然后直接操作生成需要的字节码文件,写出或者不写出,用新的字节码去生成代理对象。