一、设计模式
一、概念
代理模式是Java常见的设计模式之一。所谓代理模式是指客户端并不直接调用实际的对象,而是通过调用代理,来间接的调用实际的对象。 为什么要采用这种间接的形式来调用对象呢?一般是因为客户端不想直接访问实际的对象,或者访问实际的对象存在困难,因此通过一个代理对象来完成间接的访问。
静态代理
动态代理【JDK动态代理、CGLIB动态代理】
二、代理模式关系图

从UML图中,可以看出代理类与真正实现的类都是继承了抽象的主题类,这样的好处在于代理类可以与实际的类有相同的方法,可以保证客户端使用的透明性。
三、代理模式的角色
A、抽象的类或者接口—定义完成一件怎样的事情
B、代理对象—-完成这件事情的对象,直接面向用户的
C、被代理对象—完成事件背后的隐藏内容,用户看不到
二、JDk动态代理
动态代理有别于静态代理,是根据代理的对象,动态创建代理类。这样,就可以避免静态代理中代理类接口过多的问题。动态代理是实现方式,是通过反射来实现的,借助Java自带的java.lang.reflect.Proxy,通过固定的规则生成
示例:
接口
public interface MyCalculator {//加法int jia(int num1, int num2);//减法int jian(int num1, int num2);//乘法int cheng(int num1, int num2);}
实现类
package com.bjsxt.calculator.impl;import com.bjsxt.calculator.MyCalculator;import com.bjsxt.util.Log4JSxt;public class MyCalculatorImpl implements MyCalculator {@Overridepublic int jia(int num1, int num2) {int z=num1+num2;return z;}@Overridepublic int jian(int num1, int num2) {int z=num1-num2;return z;}@Overridepublic int cheng(int num1, int num2) {int z=num1*num2;return z;}}
jdk代理类
package com.bjsxt.proxy;import com.bjsxt.calculator.MyCalculator;import com.bjsxt.util.Log4JSxt;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;//JDK动态代理public class JDKProxy {//在虚拟机中动态的产生代理对象--中介public Object getProxy(Object o){//[1]调用getProxy接收new MyCalculatorImpl()这个对象,虚拟机创建了$proxy.class这个代理类对象(实现了MyCalculatorImpl的接口)return Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), new Class[]{MyCalculator.class}, new InvocationHandler() {/*[2]用户调用代理类proxy的方法时执行,InvocationHandler().invoke* 将proxy对象、其中包含的方法和参数传入invoke方法* 暴露给用户 方便用户进行功能上的扩展* proxy对象利用反射进行方法的调用*///proxy:代理对象 method:需要执行方法对象 args:实参列表@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//进行功能的扩展 例如:添加日志Log4JSxt.log(args[0],args[1],method.getName());//利用反射 调用目标函数中方法(房东对象)Object invoke = method.invoke(o, args);return invoke;}});}}
扩展的日志
package com.bjsxt.util;
public class Log4JSxt {
      public   static   void    log(Object num1,Object num2,String  method){
          System.out.println("操作数A:"+num1+",操作数B:"+num2+",做了:"+method+"操作");
      }
}
测试
package com.bjsxt.test;
import com.bjsxt.calculator.MyCalculator;
import com.bjsxt.calculator.impl.MyCalculatorImpl;
import com.bjsxt.proxy.JDKProxy;
public class TestB {
    public static void main(String[] args) {
        //返回的是代理对象
        MyCalculator proxy = (MyCalculator) new JDKProxy().getProxy(new MyCalculatorImpl());
        //进行方法的调用   ----代理对象的乘法
        int rs = proxy.cheng(10, 10);
        System.out.println("结果为:"+rs);
    }
}
三、CGLIB动态代理
1.JDK动态代理存在的问题
JDK代理的产生必须要实现对应的接口的,如果没有对应的接口,这个时候代理对象就没有办法产生。
2.解决方案
3.CGLIB动态代理
cglib的原理是这样,它生成一个继承B的类型C(代理类),这个代理类持有一个MethodInterceptor,我们setCallback时传入的。 C重写所有B中的方法(方法名一致),然后在C中,构建名叫“CGLIB”+“$父类方法名$”的方法(下面叫cglib方法,所有非private的方法都会被构建),方法体里只有一句话super.方法名(),可以简单的认为保持了对父类方法的一个引用,方便调用。
这样的话,C中就有了重写方法、cglib方法、父类方法(不可见),还有一个统一的拦截方法(增强方法intercept)。其中重写方法和cglib方法肯定是有映射关系的。
实现类
package com.bjsxt.calculator.impl;
import com.bjsxt.calculator.MyCalculator;
public class MyCalculatorImpl2 {
    public int jia(int num1, int num2) {
        int  z=num1+num2;
        return z;
    }
    public int jian(int num1, int num2) {
        int z=num1-num2;
        return z;
    }
    public int cheng(int num1, int num2) {
        int z=num1*num2;
        return z;
    }
}
CGLIB代理类
package com.bjsxt.proxy;
import com.bjsxt.util.Log4JSxt;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibProxy {
    public   static   Object  getPoexy(Object  target){
        Enhancer enhancer = new Enhancer();
        //设置父类
        enhancer.setSuperclass(target.getClass());
        /**
         * 参数一:代理对象
         * 参数二:目标方法反射对象
         * 参数三:目标方法参数
         * 参数四:代理方法反射对象
         */
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                //添加扩展功能
                Log4JSxt.log(objects[0],objects[1],method.getName());
                //调用到目标函数
                Object invoke = method.invoke(target, objects);
                return invoke;
            }
        });
        //使上述操作生效 返回代理对象
        Object o = enhancer.create();
        return o;
    }
}
测试
package com.bjsxt.test;
import com.bjsxt.calculator.impl.MyCalculatorImpl2;
import com.bjsxt.proxy.CglibProxy;
public class TestC {
    public static void main(String[] args) {
        //返回的是代理对象
        MyCalculatorImpl2 poexy = (MyCalculatorImpl2) CglibProxy.getPoexy(new MyCalculatorImpl2());
        //进行方法的调用   ----代理对象的乘法
        int cheng = poexy.cheng(20, 30);
        System.out.println("结果为:"+cheng);
    }
}
                    