Agent design pattern notes

Proxy mode: The main problem to be solved is to provide convenient proxy services for access to certain resources and easy-to-use operations of object classes.

scenes to be used:

  1. Provide more basic applications through the database access level to reduce the sudden increase in the number of database connections during service expansion.
  2. Some middleware: RPC framework. After getting the interface description of the jar package, the middleware generates the corresponding proxy class when the service starts. When the interface is called, the socket information is actually sent through the proxy class.
  3. MyBatis basically defines the interface but does not need to write the implementation class. You can add, delete, modify and check the SQL statements in mapper.xml or annotations.

structure:

  • Abstract theme role: Declares a common interface between the real theme and the agent theme.
  • Agent theme role: The internal contains a common interface to the real theme and the agent theme.
  • Real theme role: Define real objects.

 Spring AOP is based on dynamic proxy . If the object to be proxied implements a certain interface, then Spring AOP will use JDK Proxy to create proxy objects. For objects that do not implement the interface, JDK Proxy cannot be used for proxying. At this time, Spring AOP will use Cglib  . At this time, Spring AOP will use  Cglib to  generate a subclass of the proxy object as a proxy, as shown in the following figure:

SpringAOPProcess

 Of course, you can also use AspectJ, Spring AOP has integrated AspectJ , AspectJ should be regarded as the most complete AOP framework in the Java ecosystem.

Extensions-the difference between Spring AOP and AspectJ AOP

Dynamic proxy in 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;
}

 To get the proxy object, you need to use the java.lang.reflect.Proxy class to dynamically create it.

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

 

 Example 1:

// 简单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 dynamic agent

CGLIB uses this package to implement dynamic proxy design patterns without interfaces

CGLIB is a powerful, high-performance code generation library. It is widely used in AOP frameworks (Spring, dynaop) to provide method interception operations. Hibernate, as a more popular ORM framework, also uses CGLIB to proxy single-ended (many-to-one and one-to-one) associations (another mechanism used by delayed collections)

When using CGLIB, the corresponding relationship must be clear:

  • Proxy  -> net.sf.cglib.proxy.Enhancer;
  • InvocationHandler  -> net.sf.cglib.proxy.MethodInterceptor;
  • Real theme call: 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方法
 * 提交进行事务操作
 */

 

 

 

Guess you like

Origin blog.csdn.net/weixin_39443483/article/details/113803952