java技术--代理(proxy)模式

1.代理的意义在于生成代理对象,在服务提供方和使用方之间充当一个媒介,控制真实对象的访问
2.代理分为静态代理和动态代理两种

(1)静态代理需要通过手动或工具生成代理类并编译,代理类和委托类的关系在编译期就已经确定
(2)动态代理允许在运行时动态的创建出代理类及其对象
   <1>Spring AOP 的主要技术基础就是 Java 的动态代理机制
   <2>拦截器主要就是靠动态代理实现
      1.它可以简化动态代理的使用
      2.只需要知道拦截器接口的使用方法即可,无须知道动态代理的实现细节
   <3>拦截器在Spring AOP与Spring MVC中都有应用
      1.在 Spring AOP 中:
        1.1.针对接口做代理默认使用的是 JDK 自带的 Proxy+InvocationHandler
        1.2.针对类做代理使用的是 Cglib
      2.在 Spring MVC中:
        2.1.主要通过 HandlerInterceptor 接口实现拦截器的功能
        2.2. HandlerInterceptor 接口中包含3个方法:   
         2.2.1.preHandle:执行controller处理之前执行,返回值为true时接着执行postHandle和afterCompletion,返回false则中断执行
         2.2.2.postHandle:在执行controller后,ModelAndView 处理前执行
         2.2.3.afterCompletion:在执行完ModelAndView之后执行
        2.3.Spring MVC提供了抽象类HandlerInterceptorAdapter,实现了HandlerInterceptor接口

3.静态代理

(1)静态代理的实现需要一个接口(表示要完成的功能),一个真实对象和一个代理对象(两者都需实现这个接口)
(2)代码示例如下:
    <1>定义一个接口
    interface Shopping {void buy();}
    <2>实例对象实现接口
    class Client implements Shopping {
        //实例对象实现接口方法
        public void buy() {System.out.println("我想买这件商品");}}
    <3>代理对象实现接口
    class StaticProxy implements Shopping {
        private Shopping shopping;
        //构造方法
        public StaticProxy(Shopping shopping) {this.shopping = shopping;}
        //代理对象实现接口方法
        public void buy() {System.out.println("降价促销,疯狂大甩卖了!");
            shopping.buy();}}
     <4>测试类(客户端)
     public class StaticProxyTest {
        public static void main(String[] args) {
        //创建真是对象
        Client client = new Client();
        //创建代理对象,将真实对象交给代理对象管理
        StaticProxy service = new StaticProxy(client);
        service.buy();}}
    <5>输出结果:降价促销,疯狂大甩卖了!我想买这件商品

4.动态代理

(1)动态代理是一个实现在类创建时在运行时指定的接口列表的类,解耦程度更高
(2)动态代理接口是由动态代理类实现的接口,代理实例是代理类的一个实例
(3)Java 动态代理的实现主要借助于 java.lang.reflect 包中的 Proxy 类与 InvocationHandler 接口
(4)实现每个代理实例都有一个关联的调用处理程序对象,它实现了接口InvocationHandler
(5)通过其代理接口之一的代理实例上的方法调用将被分派到实例调用处理程序的invoke方法,传递代理实例
(6)一般称实现了InvocationHandler接口的类为调用处理器
(7)可以通过Proxy的静态工厂方法newProxyInstance创建动态代理类实例
   <1>方法如下:
   public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
     1.loader:类加载器
     2.interfaces:类实现的全部接口
     3.h:调用处理器
(8)代码示例如下:
    <1>创建动态代理实例
       public class DynamicProxy implements InvocationHandler {
           //定义一个实例对象
           private Object target = null;
          //无参都构造函数
           DynamicProxy() {}
          //有参的构造函数
           DynamicProxy(Object target) {this.target = target;}
        //将Proxy.newProxyInstance方法放到调用处理器中,简化客户端编程(参数为实例对象)
        public Object bind(Object target) {
           this.target = target;
           return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);}
    /**
     * 代理方法逻辑
     * @param proxy  代理对象
     * @param method 调度方法
     * @param args   调度方法参数
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("代理前");
        method.invoke(target, args);
        System.out.println("代理后");
        return null;}}
    <2>测试类(客户端)
    public class DyProxyTest {
    public static void main(String[] args) {
        Shopping client = new Client();
        DynamicProxy dyProxy = new DynamicProxy();
        Shopping shop = (Shopping) dyProxy.bind(client);
        shop.buy();}}

5.拦截器

(1)拦截器主要就是靠动态代理实现,它可以简化动态代理的使用
(2)只需要知道拦截器接口的使用方法即可,无须知道动态代理的实现细节
(3)开发者只需要知道拦截器的作用,设置拦截器即可
(4)代码示例如下:
    <1>定义拦截器接口
      public interface Interceptor {
         public boolean before(Object proxy, Object target, Method method, Object[] args);
         public void around(Object proxy, Object target, Method method, Object[] args);
         public void after(Object proxy, Object target, Method method, Object[] args);}
     <2>拦截器接口实现类
      public class MyInterceptor implements Interceptor {
         @Override
         public boolean before(Object proxy, Object target, Method method, Object[] args) {
              System.out.println("before");
              return false;}
         @Override
         public void around(Object proxy, Object target, Method method, Object[] args) {
             System.out.println("around");}
         @Override
         public void after(Object proxy, Object target, Method method, Object[] args) {
            System.out.println("after");}}
     <3>创建动态代理实例
      public class InterceptorProxy implements InvocationHandler {
        private Object target = null;
        Interceptor interceptor = null;
        //有参的构造函数
        InterceptorProxy(Interceptor interceptor) {this.interceptor = interceptor;}
      //将Proxy.newProxyInstance方法放到调用处理器中,简化客户端编程(参数为实例对象)
      public Object bind(Object target) {
        this.target = target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }
    /**
     * 代理方法逻辑
     * @param proxy  代理对象
     * @param method 调度方法
     * @param args   调度方法参数
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (interceptor == null) {
            method.invoke(target, args);}
            Object result = null;
        if (interceptor.before(proxy, target, method, args)) {
            result = method.invoke(target, args);
        } else {
            interceptor.around(proxy, target, method, args);}
            interceptor.after(proxy, target, method, args);
            return result;}}
    <4>测试类(客户端)
     public class InerceptorTest {
        public static void main(String[] args) {
        InterceptorProxy interceptor = new InterceptorProxy(new MyInterceptor());
        Shopping shop = (Shopping) interceptor.bind(new Client());
        shop.buy();}}
   <5>输出结果:before,around,after        

6.CGLIB(Code Generation Library):代码生成包

(1)CGLIB是一个功能强大,高性能的代码生成包,它比使用java反射的JDK动态代理要快
    <1>广泛的被许多AOP的框架使用,例如Spring AOP和dynaop
    <2>Hibernate使用CGLIB来代理单端single-ended(多对一和一对一)关联
(2)它为没有实现接口的类提供代理,为JDK的动态代理提供了很好的补充
(3)不足:对于final方法,无法进行代理
(4)使用 CGLIB和JDK自带的动态代理区别:
    <1>CGLIB代理主要通过对字节码的操作,为对象引入间接级别,以控制对象的访问
    <2>CGLIB相比于JDK动态代理更加强大
    <3>JDK动态代理虽然简单易用,但是其有一个致命缺陷是,只能对接口进行代理
    <4>如果要代理的类为一个普通类、没有接口,那么Java动态代理就没法使用了
    <5>
(5)代码示例如下:
    <1>被代理的类:定义一个类,该类没有实现任何接口    
   public class Client {
    public void buy() {
        System.out.println("我想买这件商品");}}
       @Override
       public String toString() {
        return "Client []"+ getClass();}}
    <2>定义一个拦截器
      //目标对象拦截器,实现MethodInterceptor
      public class ClientProxy implements MethodInterceptor{
    /**
     * 重写方法拦截在方法前和方法后加入业务
     * Object obj为目标对象
     * Method method为目标方法
     * Object[] params 为参数,
     * MethodProxy proxy CGlib方法代理对象
     */
      @Override
      public Object intercept(Object obj, Method method, Object[] params,
            MethodProxy proxy) throws Throwable {
        System.out.println("调用前");
        Object result = proxy.invokeSuper(obj, params);
        System.out.println(" 调用后"+result);
        return result;}}
     1.在调用目标方法时,CGLib会回调MethodInterceptor接口方法拦截,类似于JDK中的InvocationHandler接口
     2.proxy.invokeSuper(obj,arg)调用代理类实例上的proxy方法的父类方法(即实体类Client中对应的方法)
   <3>测试类:生成动态代理类
     public class CglibTest {
       public static void main(String[] args) {
          ClientProxy clientProxy = new ClientProxy();
          //创建一个字节码增强器
          Enhancer enhancer = new Enhancer();
          //将被代理的实例类设置成父类
          enhancer.setSuperclass(Client.class);
          //设置拦截器
          enhancer.setCallback(clientProxy);
          //动态生成一个代理类,并强制转化目标实例
          Client client = (Client) enhancer.create();
          //在代理类上调用方法
          client.buy();}
      1.Enhancer类是CGLib中的一个字节码增强器,它可以方便的对想要处理的类进行扩展 
      2.首先将被代理类Client设置成父类
      3.然后设置拦截器ClientProxy
      4.最后执行enhancer.create()动态生成一个代理类,并从Object强制转型成父类型Client,在代理类上调用方法
    <4>输出结果:before,我想买这件商品,after  
发布了143 篇原创文章 · 获赞 10 · 访问量 7523

猜你喜欢

转载自blog.csdn.net/qq591009234/article/details/103983640
今日推荐