First of all, let’s briefly explain what the proxy mode is.
Proxy is a design pattern that provides another way to access the target object; that is, access the target object through the proxy object. The advantage of this is that it can enhance the target object based on the implementation of the target object. Additional functional operations, that is, extending the functions of the target object.
An idea in programming is used here: do not modify the code or methods that have been written by others at will. If you need to modify it, you can extend it through a proxy. Method
Give an example to illustrate the role of an agent: Suppose we want to invite a star, then we do not directly contact the star, but contact the star's agent to achieve the same purpose. The star is a target object , he only needs to be responsible for the program at the event, and other trivial matters are left to his agent (broker) to solve. This is an example of agency thinking in reality.
The diagram is as follows:
The key points of the proxy mode are: proxy object and target object. The proxy object is an extension of the target object and will call the target object
1.1. Static Proxy
When using a static proxy, you need to define an interface or a parent class. The proxy object and the proxy object implement the same interface or inherit the same parent class.
The following is a case 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. At this time, if you use the static proxy method, you need to in the proxy object (UserDaoProxy.java) Also implements the IUserDao interface. When calling, call the target object 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 example:
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("提交事务..."); } }
(Learning video sharing:java video tutorial)
Test class:App.java
/** * 测试类 */public class App { public static void main(String[] args) { //目标对象 UserDao target = new UserDao(); //代理对象,把目标对象传给代理对象,建立代理关系 UserDaoProxy proxy = new UserDaoProxy(target); proxy.save();//执行的是代理的方法 } }
Static agent summary:
1. It can be done without modifying the target Under the premise of the function of the object, the target function is expanded.
2. Disadvantages:
Because the proxy object needs to implement the same interface as the target object, there will be many proxy classes, too many classes. At the same time, once When adding methods to the interface, both the target object and the proxy object must be maintained.
How to solve the shortcomings of static proxy? The answer is that you can use dynamic proxy method
1.2. Dynamic proxy
Dynamic proxy has the following characteristics:
1. Proxy object does not need to implement the interface
2. The generation of proxy object is to use the API of JDK to dynamically build the proxy object in the memory (we need to specify the creation of proxy object /The type of interface implemented by the target object)
3. Dynamic proxy is also called: JDK proxy, interface proxy
API for generating proxy objects in JDK
The package where the proxy class is located: 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 receives The three parameters are:
ClassLoader loader,: specifies the current target object to use the class loader, and the method of obtaining the loader is fixed
Class>[] interfaces,: target The type of interface implemented by the object, use generics to confirm the type
InvocationHandler h: event processing, when executing the method of the target object, the method of the event processor will be triggered, and the method of the currently executed target object will be used as a parameter Pass in
code example:
interface class IUserDao.java and 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 first establish the connection between the target object and the proxy object in the test class (the code that needs to use the proxy), and then use the method of the same name in the proxy object
Agent 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 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, at this time you can use the target object subclass to implement the proxy. This method is called: Cglib proxy
Cglib代理,也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展.
JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口,如果想代理没有实现接口的类,就可以使用Cglib实现.Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展java类与实现java接口.它广泛的被许多AOP的框架使用,例如Spring AOP和synaop,为他们提供方法的interception(拦截)Cglib包的底层是通过使用一个小而块的字节码处理框架ASM来转换字节码并生成新的类.不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉.
Cglib子类代理实现方法:
1.需要引入cglib的jar文件,但是Spring的核心包中已经包括了Cglib功能,所以直接引入pring-core-3.2.5.jar即可.
2.引入功能包后,就可以在内存中动态构建子类
3.代理的类不能为final,否则报错
4.目标对象的方法如果为final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法.
代码示例:
目标对象类:UserDao.java
/** * 目标对象,没有实现任何接口 */public class UserDao { public void save() { System.out.println("----已经保存数据!----"); } }
Cglib代理工厂: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; } }
测试类:
/** * 测试类 */public class App { @Test public void test(){ //目标对象 UserDao target = new UserDao(); //代理对象 UserDao proxy = (UserDao)new ProxyFactory(target).getProxyInstance(); //执行代理对象的方法 proxy.save(); } }
在Spring的AOP编程中:
如果加入容器的目标对象有实现接口,用JDK代理
如果目标对象没有实现接口,用Cglib代理
相关推荐:java入门教程
The above is the detailed content of What are the three proxy modes of java?. For more information, please follow other related articles on the PHP Chinese website!