java23中设计模式之代理模式

Posted 周无极

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java23中设计模式之代理模式相关的知识,希望对你有一定的参考价值。

1.staicproxy ---静态代理

                      一).代理模式(proxy  pattern)  核心作用:

                                     1).通过代理,控制对对象的访问!

                                     2).可以详细控制访问某个对象的方法,在调用这个方法前做前置处理,调用这个方法后做后置处理

                           二).应用场景

                                     1).安全代理:屏蔽对真实脚色真实访问

                                     2).远程代理: 通过代理类处理远程方法调用(RMI)

                                     3).延迟加载:先加载轻量级的代理对象,真正需要在加载真实对象

                           三).分类

                                     1).静态代理(静态定义代理类)

                                      2).动态生成代理类(动态生成代理类)

                                             --JDK自带的动态代理

                                            --javaassist字节码操作库实现

                                            --Cglib    类库实现

                                           --ASM (底层使用指令,可维护性较差)

 

package cn.sxt.service;

public interface UserService {
    public void add();
    public void update();
    public void delete();
    public void search();
}
UserService
package cn.sxt.service;

public class UserServiceImpl implements UserService {

    @Override
    public void add() {
        //公共的业务----日志,安全,权限,缓存,事务等等
        //A.log();---分离的思想--纸质阅读器;osgi--java模块开发-spring--osgi
        System.out.println("增加用户");
    }

    @Override
    public void update() {
        
        System.out.println("修改用户");
    }    

    @Override
    public void delete() {
        System.out.println("删除用户");
    }

    @Override
    public void search() {
        System.out.println("查询用户");
    }
}
UserServiceImpl
package cn.sxt.service;

public class UserServiceProxy implements UserService{
    private UserService userService;
    public UserServiceProxy(UserService userService) {
        super();
        this.userService = userService;
    }
    
    public UserServiceProxy() {
        super();
    }

    @Override
    public void add() {
        log("add");
        userService.add();
    }
    @Override
    public void delete() {
        //日志,安全,缓存,事务,异常处理等
        log("delete");
        userService.delete();
    }
    @Override
    public void search() {
        log("search");
        userService.search();
    }
    public void update() {
        log("update");
        userService.update();
    }
    public void log(String methodName){
        System.out.println("执行"+methodName+"方法");
    }
    
}
UserServiceProxy
package cn.sxt.service;

public class Test {
 public static void main(String[] args) {
       UserServiceProxy proxy=new UserServiceProxy(new UserServiceImpl());  
       proxy.add();
       proxy.update();
       proxy.delete();
       proxy.search();
     
     
}
}
/*执行add方法
增加用户
执行update方法
修改用户
执行delete方法
删除用户
执行search方法
查询用户
*/
Test

 

2.dynamicproxy动态代理

            一)动态代理相比静态代理的优点

                      1).抽象角色中(接口)声明的 所以方法都被转移到调用处理器一个集中的地方处理,这样,我们可以更加灵活

                            和统一的处理众多的方法 

                       2)开发框架中应用场景:

                                --stuts2 中拦截器的实现

                                --数据库连接池关闭处理

                               --hibernate 中延迟加载的实现

                              -- mybatis中实现拦截器插件

                               -- Aspect的实现

                               --spring中AOP 的实现

                                        日志拦截和声明式实物处理

                                 --web  service   RMI  远程方法调用 

                       二).JDK动态代理中包含一个类和一个接口: 
                                    InvocationHandler接口: 
                                    public interface InvocationHandler { 
                                                   public Object invoke(Object proxy,Method method,Object[] args) throws Throwable; 
                                      } 
                         参数说明: 
                                              Object proxy:指被代理的对象。 
                                              Method method:要调用的方法 
                                              Object[] args:方法调用时所需要的参数 

                              可以将InvocationHandler接口的子类想象成一个代理的最终操作类,替换掉ProxySubject。 

                      三).Proxy类: 
                                      Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,此类提供了如下的操作方法: 
                                          public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, 
                                                   InvocationHandler h) 
                                              throws IllegalArgumentException 
                               参数说明: 
                                            ClassLoader loader:类加载器 
                                            Class<?>[] interfaces:得到全部的接口 
                                            InvocationHandler h:得到InvocationHandler接口的子类实例 

                         四).Ps:类加载器 
                                          在Proxy类中的newProxyInstance()方法中需要一个ClassLoader类的实例,ClassLoader实际上对应的是类加载器,在Java中主要有一下三种类加载器; 
                                          Booststrap ClassLoader:此加载器采用C++编写,一般开发中是看不到的; 
                                           Extendsion ClassLoader:用来进行扩展类的加载,一般对应的是jre\\lib\\ext目录中的类; 
                                          AppClassLoader:(默认)加载classpath指定的类,是最常使用的是一种加载器。 

version1

package cn.sxt.dynamicproxy;

import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;

import cn.sxt.service.UserService;
import cn.sxt.service.UserServiceImpl;

public class Client {
    public static void main(String[] args) {
        System.out.println("userService+++++++++++++++++++++++++++++++");
        UserService userService = new UserServiceImpl();
        ProxyInovationHandler pih = new ProxyInovationHandler(userService);
        UserService proxy = (UserService)pih.getProxy();
        proxy.delete();
        

        System.out.println("list+++++++++++++++++++++++++++++++");
        ProxyInovationHandler ph1 = new ProxyInovationHandler(new ArrayList());
        List list = (List)ph1.getProxy();
        list.add(1);
        System.out.println(list.get(0));
    }
}
/*userService+++++++++++++++++++++++++++++++
执行delete方法
前置
删除用户
后置
list+++++++++++++++++++++++++++++++
执行add方法
前置
后置
执行get方法
前置
后置
1
*/
Client
package cn.sxt.dynamicproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyInovationHandler implements InvocationHandler{
    
    private Object target;//目标对象--真实对象
    
    
    public ProxyInovationHandler() {
        super();
    }
    
    public ProxyInovationHandler(Object i) {
        super();
        this.target = i;
    }
    
    public Object getProxy(){
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    /**
     * proxy是代理类
     * method 代理类的调用处理程序的方法对象
     * */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        System.out.println("执行"+method.getName()+"方法");
        System.out.println("前置");
        Object result = method.invoke(target, args);
        System.out.println("后置");
        return result;
    }
}
ProxyInovationHandler
package cn.sxt.service;

public interface UserService {
    public void add();
    public void update();
    public void delete();
    public void search();
}
UserService
package cn.sxt.service;

public class UserServiceImpl implements UserService {

    @Override
    public void add() {
        System.out.println("增加用户");
    }

    @Override
    public void update() {
        System.out.println("修改用户");
    }    

    @Override
    public void delete() {
        System.out.println("删除用户");
    }

    @Override
    public void search() {
        System.out.println("查询用户");
    }

}
UserServiceImpl

version 2

package com.ndqn.proxy;

public interface Start {
    /**
     * 面谈
     */
    void confer();
    /**
     * 签合同
     */
    void signContract();
    /**
     * 订票
     */
    void bookTicket();
    /**
     * 唱歌
     */
    void sing();
    /**
     * 收钱
     */
    void collectMoney();    
    
}
star
package com.ndqn.proxy;


public class RealStar implements Start {

    @Override
    public void bookTicket() {
        System.out.println("RealStar.bookTicket()");
    }

    @Override
    public void collectMoney() {
        System.out.println("RealStar.collectMoney()");
    }

    @Override
    public void confer() {
        System.out.println("RealStar.confer()");
    }

    @Override
    public void signContract() {
        System.out.println("RealStar.signContract()");
    }

    @Override
    public void sing() {
        System.out.println("RealStar(周杰伦sing()");
    }
    
    
    
}
realstar
package com.ndqn.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class StarHandle implements InvocationHandler {
     Start realStart;
     
    public StarHandle(Start realStart) {
        super();
        this.realStart = realStart;
    }


    @Override
    public Object invoke(Object proxy, Method method,
            Object[] args) throws Throwable {
         Object object = null;
        
        System.out.println("真正的方法执行前!");
        System.out.println("面谈,签合同,预付款,订机票");
        
        if(method.getName().equals("sing")){
            object = method.invoke(realStart, args);
        }
        System.out.println("真正的方法执行后!");
        System.out.println("收尾款");
        return object;
    }

}
starHandle
package com.ndqn.proxy;
/**
 * 妯℃嫙鍔ㄦ�鐢熸垚鐨勪唬鐞嗙殑缁撴瀯
 * @author Administrator
 *
 */
public class ProxyStar implements Start {
    
    StarHandle handler;
    
    public ProxyStar(StarHandle handler) {
        super();
        this.handler = handler;
    }

    public void bookTicket() {
//        handler.invoke(this,当前方法 , args);
    }

    public void collectMoney() {
//        handler.invoke(this,当前方法 , args);
    }

    public void confer() {
//        handler.invoke(this,当前方法, args);
    }

    public void signContract() {
//        handler.invoke(this,当前方法 , args);
    }

    public void sing() {
//        handler.invoke(this,当前方法 , args);
    }

}
proxy动态生成的代理类
package com.ndqn.proxy;


import java.lang.reflect.Proxy;

public class Client {
    public static void main(String[] args) {
        
        Start realStar = new RealStar();
        StarHandle handler = new StarHandle(realStar);
        
        Start proxy = (Start) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), 
                new Class[]{Start.class}, handler);
        
        proxy.sing();
        
    }
    
}
client

3.带有AOP的动态代理模式类图:

 

从上图中,可以看出有两个相对独立的模块(Subject和InvocationHandler)。动态代理实现代理的职责,业务逻辑Subject实现相关的逻辑功能,两者之间没有必然的相互耦合的关系。然而,通知Advice从另一个切面切入,最终在上层模块就是Client耦合,完成逻辑的封装。

代码清单如下

抽象主题或者接口:

package com.yemaozi.proxy.dynamic_aop;
 
 public interface Subject {
     public void doSomething(String str);
    //...可以多个逻辑处理方法。。。
 }
Subject
package com.yemaozi.proxy.dynamic_aop;
  
  public class RealSubject implements Subject{
  
     public void doSomething(String str) {
          //do something...
          System.out.println("do something..." + str);
      }
  
 }
RealSubject
package com.yemaozi.proxy.dynamic_aop;
 
 //通知接口及定义、
 public interface IAdvice {
     public void exec();
 }
IAdvice
package com.yemaozi.proxy.dynamic_aop;
  public class BeforeAdvice implements IAdvice {
     //在被代理的方法前来执行,从而达到扩展功能。
   public void exec() {
         System.out.println("前置通知被执行!");
    }
 }
BeforeAdvice
package com.yemaozi.proxy.dynamic_aop;
  public class AfterAdvice implements IAdvice {
     
     //在被代理的方法后来执行,从而达到扩展功能。
     public void exec() {
         System.out.println("后置通知被执行!");
     }
 }
AfterAdvice
package com.yemaozi.proxy.dynamic_aop;

 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Method;

public class MyInvocationHandler implements InvocationHandler {

   //被代理的对象
     private Subject realSubject;
   //通过MyInvocationHandler的构造方法将被代理对象传递过来。
    public MyInvocationHandler(Subject realSubject){
        this.realSubject = realSubject;
     }
     //执行被代理类的方法。
     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //在执行方法前,执行前置通知。
         IAdvice beforeAdvice = new BeforeAdvice();
         beforeAdvice.exec();
         Object result = method.invoke(this.realSubject, args);
        //在执行方法后,执行后置通知。
         IAdvice afterAdvice = new AfterAdvice();
         afterAdvice.exec();
        //前置通知,和后置通知,都是要看具体实际的业务需求来进行添加。
         return result;
     }
 
 }
MyInvocationHandler
package com.yemaozi.proxy.dynamic_aop;

 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Proxy;

 public class DynamicProxy {
     
     /**
     * public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler handler)
     * loader:
      *             一个ClassLoader对象,定义了由哪个ClassLoader对象,来对生产的代理进行加载。
    * interfaces:
      *             一个Interfaces数组,表示我将要给我所代理的对象提供一组什么样的接口,
     *             如果提供一组接口给它,那么该代理对象就宣称实现了该接口,从而可以调用接口中的方法。
     *             即,查找出真是主题类的所实现的所有的接口。
      * handler:
      *             一个InvocationHandler对象,表示当我这个动态代理对象在调用方法时,会关联到该InvocationHandler对象。
    *             该InvocationHandler与主题类有着关联。
     */
    public static <T> T newProxyInstance(ClassLoader classLoader, Class<?>[] interfaces, InvocationHandler handler){
         @SuppressWarnings("unchecked")
         T t = (T) Proxy.newProxyInstance(classLoader, interfaces, handler);
        return t;
    }
 }
DynamicProxy
package com.yemaozi.proxy.dynamic_aop;
 
import java.lang.reflect.InvocationHandler;

public class AOPClient {
   
    public static void main(String[] args) {
         Subject realSubject = new RealSubject();
         InvocationHandler handler = new MyInvocationHandler(realSubject); 
         ClassLoader classLoader = realSubject.getClass().getClassLoader();
         Class<?>[] interfaces = realSubject.getClass().getInterfaces();
       Subject proxySubect = DynamicProxy.newProxyInstance(classLoader, interfaces, handler);
        proxySubect.doSomething("这是一个Dynamic AOP示例!!!");
     }
 }
 
 执行结果:
 前置通知被执行!
 do something...这是一个Dynamic AOP示例!!!
后置通知被执行!
AOPClient

动态代理在现在用的是非常的多的,如像Spring AOP ,DBCP连接池,AspectJ等。。。

4. Cglib动态代理 
JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。 
示例 

package com.bdqn.ulist;
/**
 *这个是没有实现接口的实现类
 * 
 * @author admin
 *
 */
public class BookCadeImpl {
    public void add() {  
        System.out.println("This is add service");  
    }  
    public void delete(int id) {  
        System.out.println("This is delete service:delete " + id );  
    }  
}
BookCadeImpl
package com.bdqn.ulist;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
 * 使用cglib动态代理
 */
public  class BookFacadeCglib implements MethodInterceptor {
    Object target;
    public Object getInstance(Object target){
        this.target=target;
        Enhancer enhancer=new Enhancer();
        enhancer.setSuperclass(this.target.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }
    //回调方法
    public Object intercept(Object obj, Method method, Object[] arg,
            MethodProxy proxy) throws Throwable {
        System.out.println("事务开始");
        Object ob=proxy.invokeSuper(obj, arg);
        System.out.println("事务结束");
        return ob;
    }

}
BookFacadeCglib
package com.bdqn.ulist;

import java.beans.Introspector;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;

public class TestCglib {
 public static void main(String[] args) {
     BookFacadeCglib interceptor=new BookFacadeCglib();
     BookCadeImpl cadeImpl<

以上是关于java23中设计模式之代理模式的主要内容,如果未能解决你的问题,请参考以下文章

springAOP之代理模式

23中设计模式之-代理模式

java代码实现设计模式之代理模式

Java设计模式-代理模式之动态代理(附源代码分析)

23天设计模式之代理模式

Java学习笔记——设计模式之四.代理模式