代理设计模式笔记

代理模式:主要解决的问题是为某些资源的访问、对象的类的易用操作上提供方便使用的代理服务。

使用场景:

  1. 通过数据库访问层面提供较为基础的应用,来减少服务扩展时数据库连接数陡增的情况。
  2. 一些中间件:RPC框架。在拿到jar包的接口描述后,中间件在服务启动的时候生成对应的代理类,当调用接口的时候,实际是通过代理类发出socket信息。
  3. MyBatis,基本是定义接口但是不需要写实现类,就可以对mapper.xml或者注解里的sql语句进行增删改查操作。

结构:

  • 抽象主题角色:声明了真实主题和代理主题的共同接口。
  • 代理主题角色:内部包含了对真实主题和代理主题的共同接口。
  • 真实主题角色:定义真实对象。

 Spring AOP 就是基于动态代理的,如果要代理的对象,实现了某个接口,那么Spring AOP会使用JDK Proxy,去创建代理对象,而对于没有实现接口的对象,就无法使用 JDK Proxy 去进行代理了,这时候Spring AOP会使用Cglib ,这时候Spring AOP会使用 Cglib 生成一个被代理对象的子类来作为代理,如下图所示:

SpringAOPProcess

 当然你也可以使用 AspectJ ,Spring AOP 已经集成了AspectJ ,AspectJ 应该算的上是 Java 生态系统中最完整的 AOP 框架了。

扩展--Spring AOP 和AspectJ AOP区别

JDK中的动态代理

InvocationHandler中的invoke()方法属于代理类中调用真实主题类的方法,但是该方法没有所对应的真实主题类,需要在创建对象时设置真实主题。

package java.lang.reflect;

public interface InvocationHandler {
    /**
     * Object proxy:代理类的对象[代理后的类]
     * Method method:需要调用的方法
     * Object[] args:方法所需的参数
     */
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

 若要得到代理对象需使用java.lang.reflect.Proxy类动态创建。

/**
 * ClassLoader loader:取得对象的加载器
 * Class<?>[] interfaces:代理模式的核心是围绕接口进行的,所以需取出全部接口
 * InvocationHandler h:代理实现类
public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)

 

 示例一:

// 简单Java类
public class Dept {
}


// 定义的接口层
public interface IDeptDAO {
    boolean doCreate(Dept vo) throws Exception;
    List<Dept> findAll() throws Exception;
}

// 具体接口实现
public class DeptDAOImpl implements IDeptDAO{
    @Override
    public boolean doCreate(Dept vo) throws Exception {
        System.out.println("执行数据增加操作");
        return false;
    }

    @Override
    public List<Dept> findAll() throws Exception {
        System.out.println("执行数据查询操作");
        return null;
    }
}

//动态代理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class DAOProxy implements InvocationHandler {
    // 不能与具体的DAO耦合在一起
    private Object obj ; // 真实主题类--需要代理的

    /**
     * 将真实主题类绑定到代理中,返回一个被代理后的对象
     * @param obj 真实主题类
     * @return 代理后的对象
     */
    public Object bind(Object obj){

        // !!!!要保存真实主题类--便于后面的方法执行!!!!
        this.obj = obj ;
        /**
         * -----由Java系统实现的代理
         * obj.getClass().getClassLoader() : 通过反射取得该真实主题类的类加载器
         * obj.getClass().getInterfaces() : 通过反射取得真实主题的所有接口
         * this: 由于当前DAOProxy实现了InvocationHandler,所以是代理类
         */
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
    }

    public void prepare(){
        System.out.println("*************取消JDBC的自动提交***************");
    }

    public void commit(){
        System.out.println("*************手动提交JDBC事务***************");
    }

    public void rollback(){
        System.out.println("*************手动回滚JDBC事务***************");
    }

    // 只要执行了方法,就会触发执行invoke()方法
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = null ; // 接收结果
        if (method.getName().contains("do")){
            // 取得方法的名称对操作进行判断
            this.prepare();
            try {
                // 反射中的知识--执行方法需要存在类的实例所以要保存this.obj
                result = method.invoke(this.obj, args);
                this.commit();
            } catch (Exception e){
                e.printStackTrace();
                rollback();
            }
        } else{
            // 如果不需要开启事务,则直接执行方法
            result = method.invoke(this.obj, args);
        }
        return result;
    }
}

// 通过工厂类隐藏具体细节
public class DAOFactory {
    public static Object getDAOInstance(){
        // 直接将真实主题类绑定到代理中返回代理后的类
        return new DAOProxy().bind(new DeptDAOImpl());
    }
}

//测试类
public class ProxyMain {
    public static void main(String[] args) throws Exception{
        IDeptDAO  dao = (IDeptDAO) DAOFactory.getDAOInstance();
        Dept dept = new Dept();
        dao.doCreate(dept);
        dao.findAll();
    }
}

/* output:
 * *************取消JDBC的自动提交***************
 * 执行数据增加操作
 * *************手动提交JDBC事务***************
 * 执行数据查询操作
 * /

CGLIB动态代理

CGLIB利用这个包可以在没有接口的情况下实现动态代理设计模式

CGLIB是一个强大的、高性能的代码生成库。其被广泛应用于AOP框架(Spring、dynaop)中,用以提供方法拦截操作。Hibernate作为一个比较受欢迎的ORM框架,同样使用CGLIB来代理单端(多对一和一对一)关联(延迟提取集合使用的另一种机制)

在使用CGLIB时,必须清楚对应关系:

  • Proxy  -> net.sf.cglib.proxy.Enhancer;
  • InvocationHandler  -> net.sf.cglib.proxy.MethodInterceptor;
  • 真实主题调用:net.sf.cglib.proxy.MethodProxy
package 代理设计模式;

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

import java.lang.reflect.Method;

class FunctionImple{
    public void create(){
        System.out.println("create方法");
    }
}
class MyProxy implements MethodInterceptor{
    private Object object; // 真实操作主题类
    public MyProxy(Object object){
        this.object = object;
    }
    public void prepre(){
        System.out.println("取消自动提交");
    }
    public void commit(){
        System.out.println("提交进行事务操作");
    }
    public void rollback(){
        System.out.println("提交失败,回滚");
    }

    
    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        Object reuslt = null;
        // 说明proxy是真实类的子类--如果被代理类是Final类就无法使用CGLIB
        // 但是ASM可以对Final进行代理
        System.out.println(proxy.getClass().getSuperclass().getName());
        this.prepre();
        // CGLIB反射调用真实对象方法
        reuslt = methodProxy.invokeSuper(proxy, args);
        this.commit();
        return reuslt;
    }
}
public class CGLIBDemo {
    public static void main(String[] args) {
        // 真实主题对象
        FunctionImple functionImple = new FunctionImple();
        // CGLIB enhancer增强类对象
        Enhancer enhancer = new Enhancer();
        // 设置增强类型--是当前类的子类
        enhancer.setSuperclass(FunctionImple.class);
        // 定义代理逻辑对象为当前对象,要求当前对象实现MethodInterceptor方法
        enhancer.setCallback(new MyProxy(functionImple));
        // 生成并返回代理对象
        FunctionImple proxyDao = (FunctionImple) enhancer.create();
        proxyDao.create();

    }
}
/**
 * 代理设计模式.FunctionImple
 * 取消自动提交
 * create方法
 * 提交进行事务操作
 */

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值