Java proxy mode

proxy mode

Proxy (Proxy) is a design pattern that provides another way of accessing the target object; that is, accessing the target object through the proxy object. The advantage of this is that additional functional operations can be enhanced based on the implementation of the target object, namely Extend the function of the target object.
Here is an idea in programming: do not arbitrarily modify the code or methods that have been written by others. If you need to modify it, you can extend the method by proxy

Give an example to illustrate the role of an agent: Suppose we want to invite a star, then instead of directly connecting with the star, we will contact the star's agent to achieve the same purpose. The star is a target, and he only needs to be responsible for the activities in the event. show, while other trivial matters are left to his agent (agent) to solve. This is an example of agency thinking in reality

It is represented by the diagram as follows:

The key points of the proxy mode are: the proxy object and the target object. The proxy object is an extension of the target object and will call the target object

1.1. Static proxy

When a static proxy is used, an interface or a parent class needs to be defined, and the proxied object and the proxy object implement the same interface or inherit the same parent class.

Let's take an example to explain:
simulate the save action, define an interface for the save action: IUserDao.java, and then the target object implements the method UserDao.java of this interface. If the static proxy method is used at this time, it needs to be in the proxy object (UserDaoProxy. java) also implements the IUserDao interface. When calling, the target object is called by calling the method of the proxy object.
It should be noted that the proxy object and the target object must implement the same interface, and then call the method of the target object by calling the same method.

Code Sample:
Interface: IUserDao.java

/**
 * 接口
 */
public interface IUserDao {

    void save();
}

Target object: UserDao.java

/**
 * 接口实现
 * 目标对象
 */
public class UserDao implements IUserDao {
    public void save() {
        System.out.println("----已经保存数据!----");
    }
}

Proxy object: UserDaoProxy.java

/**
 * 代理对象,静态代理
 */
public class UserDaoProxy implements IUserDao{
    //接收保存目标对象
    private IUserDao target;
    public UserDaoProxy(IUserDao target){
        this.target=target;
    }

    public void save() {
        System.out.println("开始事务...");
        target.save();//执行目标对象的方法
        System.out.println("提交事务...");
    }
}

Test class: App.java

/**
 * 测试类
 */
public class App {
    public static void main(String[] args) {
        //目标对象
        UserDao target = new UserDao();

        //代理对象,把目标对象传给代理对象,建立代理关系
        UserDaoProxy proxy = new UserDaoProxy(target);

        proxy.save();//执行的是代理的方法
    }
}

Summary of static proxy:
1. It is possible to extend the target function without modifying the function of the target object.
2. Disadvantages:

  • Because the proxy object needs to implement the same interface as the target object, there will be many proxy classes, and there are too many classes. At the same time, once the interface adds methods, the target object and the proxy object must be maintained.

How to solve the shortcomings of static proxy? The answer is to use dynamic proxy

1.2. Dynamic proxy

The dynamic proxy has the following characteristics:
1. The proxy object does not need to implement the interface
2. The generation of the proxy object is to use the JDK API to dynamically construct the proxy object in the memory (requires us to specify the interface implemented by the proxy object/target object) Type)
3. Dynamic proxy is also called: JDK proxy, interface proxy

The package of the API
proxy class that generates the proxy object in the JDK: java.lang.reflect.Proxy
JDK only needs to use the newProxyInstance method to implement the proxy, but this method needs to receive three parameters. The complete writing method is:

static Object newProxyInstance(ClassLoader loader, Class<?>[] 
interfaces,InvocationHandler h )

Note that this method is a static method in the Proxy class, and the three parameters received are:

  • ClassLoader loader,: Specifies that the current target object uses the class loader, and the method for obtaining the loader is fixed
  • Class<?>[] interfaces,: The type of the interface implemented by the target object, using generics to confirm the type
  • InvocationHandler h: Event processing, when the method of the target object is executed, the method of the event handler will be triggered, and the method of the currently executed target object will be passed in as a parameter

Code example:
the interface class IUserDao.java and the interface implementation class, the target object UserDao is the same, without modification. On this basis, add a proxy factory class (ProxyFactory.java), write the proxy class in this place, and then in In the test class (the code that needs to use the proxy), first establish the connection between the target object and the proxy object, and then substitute the method of the same name in the proxy object.

Proxy factory class: ProxyFactory.java

/**
 * 创建动态代理对象
 * 动态代理不需要实现接口,但是需要指定接口类型
 */
public class ProxyFactory{

    //维护一个目标对象
    private Object target;
    public ProxyFactory(Object target){
        this.target=target;
    }

   //给目标对象生成代理对象
    public Object getProxyInstance(){
        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("开始事务2");
                        //执行目标对象方法
                        Object returnValue = method.invoke(target, args);
                        System.out.println("提交事务2");
                        return returnValue;
                    }
                }
        );
    }

}

Test class: App.java

/**
 * 测试类
 */
public class App {
    public static void main(String[] args) {
        // 目标对象
        IUserDao target = new UserDao();
        // 【原始的类型 class cn.itcast.b_dynamic.UserDao】
        System.out.println(target.getClass());

        // 给目标对象,创建代理对象
        IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance();
        // class $Proxy0   内存中动态生成的代理对象
        System.out.println(proxy.getClass());

        // 执行方法   【代理对象】
        proxy.save();
    }
}

Summary:
The proxy object does not need to implement the interface, but the target object must implement the interface, otherwise dynamic proxy cannot be used

1.3. Cglib proxy

The above static proxy and dynamic proxy modes both require the target object to be a target object that implements an interface, but sometimes the target object is just a separate object and does not implement any interface. In this case, the subclass of the target object can be used. The way class implements the proxy, this method is called: Cglib proxy

Cglib proxy, also called subclass proxy, builds a subclass object in memory to extend the function of the target object.

  • JDK's dynamic proxy has a limitation, that is, the object using dynamic proxy must implement one or more interfaces. If you want to proxy a class that does not implement an interface, you can use Cglib to implement it.
  • Cglib is a powerful high-performance code generation package that can extend java classes and implement java interfaces at runtime. It is widely used by many AOP frameworks, such as Spring AOP and synaop, to provide method interception (interception) for them
  • The bottom layer of the Cglib package is to convert bytecodes and generate new classes by using ASM, a small and block bytecode processing framework. Direct use of ASM is discouraged, because it requires you to have an understanding of the JVM internal structure including the format of the class file and The instruction set is all familiar.

Cglib subclass proxy implementation method:
1. The jar file of cglib needs to be imported, but the Cglib function is already included in the core package of Spring, so it can be imported directly pring-core-3.2.5.jar.
2. After the function package is introduced, the subclass can be dynamically built in memory
3. The class of the proxy cannot be final, otherwise an error will be reported
4. If the method of the target object is final/static, it will not be intercepted, that is, the additional business methods of the target object will not be executed.

Code Sample:
Target Object Class: UserDao.java

/**
 * 目标对象,没有实现任何接口
 */
public class UserDao {

    public void save() {
        System.out.println("----已经保存数据!----");
    }
}

Cglib proxy factory: ProxyFactory.java

/**
 * Cglib子类代理工厂
 * 对UserDao在内存中动态构建一个子类对象
 */
public class ProxyFactory implements MethodInterceptor{
    //维护目标对象
    private Object target;

    public ProxyFactory(Object target) {
        this.target = target;
    }

    //给目标对象创建一个代理对象
    public Object getProxyInstance(){
        //1.工具类
        Enhancer en = new Enhancer();
        //2.设置父类
        en.setSuperclass(target.getClass());
        //3.设置回调函数
        en.setCallback(this);
        //4.创建子类(代理对象)
        return en.create();

    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("开始事务...");

        //执行目标对象的方法
        Object returnValue = method.invoke(target, args);

        System.out.println("提交事务...");

        return returnValue;
    }
}

Test class:

/**
 * 测试类
 */
public class App {

    @Test
    public void test(){
        //目标对象
        UserDao target = new UserDao();

        //代理对象
        UserDao proxy = (UserDao)new ProxyFactory(target).getProxyInstance();

        //执行代理对象的方法
        proxy.save();
    }
}

In Spring's AOP programming:

  • If the target object added to the container has an implementation interface, use the JDK proxy
  • If the target object does not implement the interface, use the Cglib proxy

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326391438&siteId=291194637