Home  >  Article  >  Java  >  In-depth understanding of java dynamic proxy

In-depth understanding of java dynamic proxy

高洛峰
高洛峰Original
2017-02-08 11:00:101224browse

Dynamic Agent of JAVA
Agent Mode
The agent mode is a commonly used java design pattern. Its characteristic is that the agent class and the delegate class have the same interface. The agent class is mainly responsible for preprocessing messages and filtering for the delegate class. Message, forward the message to the delegate class, and process the message afterwards, etc. There is usually an association between a proxy class and a delegate class. An object of a proxy class is associated with an object of a delegate class. The object of the proxy class itself does not actually implement the service, but by calling the relevant methods of the object of the delegate class. Provide specific services.
According to the creation period of the agent, the agent class can be divided into two types.
Static proxy: Created by programmers or automatically generated by specific tools, and then compiled. Before the program is run, the .class file of the proxy class already exists.
Dynamic proxy: Dynamically created using the reflection mechanism when the program is running.

First take a look at the static proxy:

1, Count.java

package net.battier.dao;  
  
/** 
 * 定义一个账户接口 
 *  
 * @author Administrator 
 *  
 */  
public interface Count {  
    // 查看账户方法  
    public void queryCount();  
  
    // 修改账户方法  
    public void updateCount();  
  
}

2, CountImpl.java

package net.battier.dao.impl;  
  
import net.battier.dao.Count;  
  
/** 
 * 委托类(包含业务逻辑) 
 *  
 * @author Administrator 
 *  
 */  
public class CountImpl implements Count {  
  
    @Override  
    public void queryCount() {  
        System.out.println("查看账户方法...");  
  
    }  
  
    @Override  
    public void updateCount() {  
        System.out.println("修改账户方法...");  
  
    }  
  
}  
  
、CountProxy.java  
package net.battier.dao.impl;  
  
import net.battier.dao.Count;  
  
/** 
 * 这是一个代理类(增强CountImpl实现类) 
 *  
 * @author Administrator 
 *  
 */  
public class CountProxy implements Count {  
    private CountImpl countImpl;  
  
    /** 
     * 覆盖默认构造器 
     *  
     * @param countImpl 
     */  
    public CountProxy(CountImpl countImpl) {  
        this.countImpl = countImpl;  
    }  
  
    @Override  
    public void queryCount() {  
        System.out.println("事务处理之前");  
        // 调用委托类的方法;  
        countImpl.queryCount();  
        System.out.println("事务处理之后");  
    }  
  
    @Override  
    public void updateCount() {  
        System.out.println("事务处理之前");  
        // 调用委托类的方法;  
        countImpl.updateCount();  
        System.out.println("事务处理之后");  
  
    }  
  
}

3, TestCount.java

package net.battier.test;  
  
import net.battier.dao.impl.CountImpl;  
import net.battier.dao.impl.CountProxy;  
  
/** 
 *测试Count类 
 *  
 * @author Administrator 
 *  
 */  
public class TestCount {  
    public static void main(String[] args) {  
        CountImpl countImpl = new CountImpl();  
        CountProxy countProxy = new CountProxy(countImpl);  
        countProxy.updateCount();  
        countProxy.queryCount();  
  
    }  
}

Observing the code, you can find that each proxy class can only serve one interface. In this way, too many proxies will inevitably be generated during program development. Moreover, all proxy operations are different except the method called. Except for the same, if other operations are the same, then the code must be repeated at this time. The best way to solve this problem is to use a proxy class to complete all proxy functions. In this case, a dynamic proxy must be used to complete it.
Let’s take a look at the dynamic proxy:
The JDK dynamic proxy contains a class and an interface:
InvocationHandler interface:

public interface InvocationHandler { 
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable; 
}

Parameter description:
Object proxy: refers to the object being proxied .
Method method: The method to be called
Object[] args: The parameters required when calling the method

You can imagine the subclass of the InvocationHandler interface as the final operation class of a proxy, replacing ProxySubject .

Proxy class:
The Proxy class is a class specifically designed to complete proxy operations. This class can be used to dynamically generate implementation classes for one or more interfaces. This class provides the following operation methods:
Public Static Object NewProxyinstance (Classloader Loader, Class & LT;? & GT; [] Interfaces,
Invocationhandler H)
Throws Ion
parameter description:
Classloader loader: class loader
Class & LT;? & GT ;[] interfaces: Get all interfaces
InvocationHandler h: Get the subclass instance of the InvocationHandler interface

Ps: Class loader
A ClassLoader class is required in the newProxyInstance() method in the Proxy class Instances of ClassLoader actually correspond to class loaders. There are three main class loaders in Java;
Booststrap ClassLoader: This loader is written in C++ and cannot be seen in general development;
Extendsion ClassLoader: used to load extended classes, generally corresponding to the classes in the jre\lib\ext directory;
AppClassLoader: (Default) loads the class specified by the classpath, which is the most commonly used loader.

Dynamic proxy
Contrast with the static proxy class is the dynamic proxy class. The bytecode of the dynamic proxy class is dynamically generated by the Java reflection mechanism when the program is running, without the need for programmers to manually write its source code. Dynamic proxy classes not only simplify programming work, but also improve the scalability of software systems, because the Java reflection mechanism can generate any type of dynamic proxy class. The Proxy class and InvocationHandler interface in the java.lang.reflect package provide the ability to generate dynamic proxy classes.

Dynamic proxy example:

1. BookFacade.java

package net.battier.dao;  
  
public interface BookFacade {  
    public void addBook();  
}

2. BookFacadeImpl.java

package net.battier.dao.impl;  
  
import net.battier.dao.BookFacade;  
  
public class BookFacadeImpl implements BookFacade {  
  
    @Override  
    public void addBook() {  
        System.out.println("增加图书方法。。。");  
    }  
  
}  
  
、BookFacadeProxy.java  
  
package net.battier.proxy;  
  
import java.lang.reflect.InvocationHandler;  
import java.lang.reflect.Method;  
import java.lang.reflect.Proxy;  
  
/** 
 * JDK动态代理代理类 
 *  
 * @author student 
 *  
 */  
public class BookFacadeProxy implements InvocationHandler {  
    private Object target;  
    /** 
     * 绑定委托对象并返回一个代理类 
     * @param target 
     * @return 
     */  
    public Object bind(Object target) {  
        this.target = target;  
        //取得代理对象  
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),  
                target.getClass().getInterfaces(), this);   //要绑定接口(这是一个缺陷,cglib弥补了这一缺陷)  
    }  
  
    @Override  
    /** 
     * 调用方法 
     */  
    public Object invoke(Object proxy, Method method, Object[] args)  
            throws Throwable {  
        Object result=null;  
        System.out.println("事物开始");  
        //执行方法  
        result=method.invoke(target, args);  
        System.out.println("事物结束");  
        return result;  
    }  
  
}

3. TestProxy.java

package net.battier.test;  
  
import net.battier.dao.BookFacade;  
import net.battier.dao.impl.BookFacadeImpl;  
import net.battier.proxy.BookFacadeProxy;  
  
public class TestProxy {  
  
    public static void main(String[] args) {  
        BookFacadeProxy proxy = new BookFacadeProxy();  
        BookFacade bookProxy = (BookFacade) proxy.bind(new BookFacadeImpl());  
        bookProxy.addBook();  
    }  
  
}

However, JDK's dynamic proxy relies on interface implementation. If some classes do not implement the interface, the JDK proxy cannot be used, so cglib dynamic proxy must be used.

Cglib dynamic proxy
JDK’s dynamic proxy mechanism can only proxy classes that implement interfaces, and classes that cannot implement interfaces cannot implement JDK’s dynamic proxy. cglib implements proxy for classes. The principle is to generate a subclass for the specified target class and override the method to achieve enhancement. However, because inheritance is used, the final modified class cannot be proxied.
Example

1, BookFacadeCglib.java

package net.battier.dao;  
  
public interface BookFacade {  
    public void addBook();  
}

2, BookCadeImpl1.java

package net.battier.dao.impl;  
  
/** 
 * 这个是没有实现接口的实现类 
 *  
 * @author student 
 *  
 */  
public class BookFacadeImpl1 {  
    public void addBook() {  
        System.out.println("增加图书的普通方法...");  
    }  
}

3, BookFacadeProxy.java

package net.battier.proxy;  
  
import java.lang.reflect.Method;  
  
import net.sf.cglib.proxy.Enhancer;  
import net.sf.cglib.proxy.MethodInterceptor;  
import net.sf.cglib.proxy.MethodProxy;  
  
/** 
 * 使用cglib动态代理 
 *  
 * @author student 
 *  
 */  
public class BookFacadeCglib implements MethodInterceptor {  
    private Object target;  
  
    /** 
     * 创建代理对象 
     *  
     * @param target 
     * @return 
     */  
    public Object getInstance(Object target) {  
        this.target = target;  
        Enhancer enhancer = new Enhancer();  
        enhancer.setSuperclass(this.target.getClass());  
        // 回调方法  
        enhancer.setCallback(this);  
        // 创建代理对象  
        return enhancer.create();  
    }  
  
    @Override  
    // 回调方法  
    public Object intercept(Object obj, Method method, Object[] args,  
            MethodProxy proxy) throws Throwable {  
        System.out.println("事物开始");  
        proxy.invokeSuper(obj, args);  
        System.out.println("事物结束");  
        return null;  
  
  
    }  
  
}

4, TestCglib. java

package net.battier.test;  
  
import net.battier.dao.impl.BookFacadeImpl1;  
import net.battier.proxy.BookFacadeCglib;  
  
public class TestCglib {  
      
    public static void main(String[] args) {  
        BookFacadeCglib cglib=new BookFacadeCglib();  
        BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1());  
        bookCglib.addBook();  
    }  
}

For more in-depth understanding of java dynamic proxy related articles, please pay attention to the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn