Last article introduced static proxies: The Proxy pattern in Java – Static proxies and analyzed the disadvantages of static proxies

A static proxy is a.class file of the proxy class that exists before the program runs.

Dynamic proxies are created dynamically using reflection while the program is running, without the need to write code manually

The disadvantages of static proxy are also analyzed:

1. Since the static proxy class is used to delegate to a particular class, if there are 100 services in a system, 100 proxy classes need to be created

2. If there are many methods in a Service that require transactions (enhanced actions), there is still a lot of duplicate code in the methods of the proxy object

3. It follows from the first and second points that static proxies are not very reusable

So what’s the solution?

Dynamic proxy can be a good solution to the above problems, this article introduces: Java dynamic proxy

The dynamic proxy implements the same purpose as the static proxy, which is to enhance the target method and separate the enhanced action from the target action to achieve decoupling

Dynamic proxies are classified into JDK dynamic proxies and Cglib dynamic proxies

There are slight differences: the JDK dynamic proxy generates a proxy class that implements the same interface as the target class; Cglib dynamic proxies produce proxy classes that are subclasses of the target object.

The following describes the JDK dynamic proxy (implemented by JDK code) and the Cglib dynamic proxy (implemented by Cglib JAR packages) respectively.

JDK dynamic proxy

package com.cj.study.proxyjdk;
 
public interface PersonService {
	
	public String savePerson(a);
	
	public void updatePerson(a);
	
	public void deletePerson(a);
	
}
Copy the code
package com.cj.study.proxyjdk;
 
public class PersonServiceImpl implements PersonService{
 
	@Override
	public String savePerson(a) {
		System.out.println("Add");
		return "Saved successfully!";
	}
 
	@Override
	public void updatePerson(a) {
		System.out.println("Change");
	}
 
	@Override
	public void deletePerson(a) {
		System.out.println("Delete"); }}Copy the code
package com.cj.study.proxyjdk;
 
public class MyTransaction {
	public void beginTransaction(a){
		System.out.println("Open transaction");
	}
	public void commit(a){
		System.out.println("Commit transaction"); }}Copy the code

Note: Dynamic proxies require an interceptor InvocationHandler when generating proxy objects, so we need to write an interceptor

package com.cj.study.proxyjdk;
 
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
 
public class PersonServiceInterceptor implements InvocationHandler{
	/ / the target class
	private Object target;
	/ / class
	private MyTransaction myTransaction;
	// The constructor injects the target class and the enhanced class
	public PersonServiceInterceptor(Object target,MyTransaction myTransaction){
		this.target = target;
		this.myTransaction = myTransaction;
	}
 
	// The invoke method below is called when each method of the proxy class is called
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		this.myTransaction.beginTransaction();
		Object returnValue = method.invoke(this.target, args);
		this.myTransaction.commit();
		returnreturnValue; }}Copy the code

Note:

1. When the client executes the proxy object. Method into the interceptor’s Invoke method body

2. The contents of the invoke method body in the interceptor are the contents of the proxy object method body

The method parameter to the invoke method in the interceptor is assigned at call time

package com.cj.study.proxyjdk;
 
import java.lang.reflect.Proxy;
import org.junit.Test;
 
public class ProxyTest {
	@Test
	public void test(a){
		Object target = new PersonServiceImpl();
		MyTransaction myTransaction = new MyTransaction();
		PersonServiceInterceptor interceptor = newPersonServiceInterceptor(target, myTransaction); PersonService personService = (PersonService)Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),interceptor); String returnValue = (String)personService.savePerson(); System.out.println(returnValue); }}Copy the code

We can stop and look at it

Finding that the generated object is $Proxy4 shows that the returned object is already our proxy object

The final run result

2. Cglib dynamic proxy

You need to import the Cglib JAR package cglib-nodeP-2.1_3.jar

package com.cj.study.proxycglib;
 
public interface PersonService {
	
	public String savePerson(a);
	
	public void updatePerson(a);
	
	public void deletePerson(a);
	
}
Copy the code
package com.cj.study.proxycglib;
 
public class PersonServiceImpl implements PersonService{
 
	@Override
	public String savePerson(a) {
		System.out.println("Add");
		return "Saved successfully!";
	}
 
	@Override
	public void updatePerson(a) {
		System.out.println("Change");
	}
 
	@Override
	public void deletePerson(a) {
		System.out.println("Delete"); }}Copy the code
package com.cj.study.proxycglib;
 
public class MyTransaction {
	public void beginTransaction(a){
		System.out.println("Open transaction");
	}
	public void commit(a){
		System.out.println("Commit transaction"); }}Copy the code
package com.cj.study.proxycglib;
 
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
 
public class PersonServiceInterceptor implements MethodInterceptor{
	/ / the target class
	private Object target;
	/ / class
	private MyTransaction myTransaction;
	// The constructor injects the target class and the enhanced class
	public PersonServiceInterceptor(Object target,MyTransaction myTransaction){
		this.target = target;
		this.myTransaction = myTransaction;
	}
	
	public Object createProxy(a){
		Enhancer enhancer = new Enhancer();
		enhancer.setCallback(this);
		enhancer.setSuperclass(this.target.getClass());
		return enhancer.create();
	}
 
	@Override
	public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable {
		myTransaction.beginTransaction();
		Object returnValue = arg1.invoke(this.target, arg2);
		myTransaction.commit();
		returnreturnValue; }}Copy the code
package com.cj.study.proxycglib;
 
import org.junit.Test;
 
public class ProxyTest {
	@Test
	public void test(a){
		Object target = new PersonServiceImpl();
		MyTransaction myTransaction = new MyTransaction();
		PersonServiceInterceptor interceptor = newPersonServiceInterceptor(target, myTransaction); PersonService personService =(PersonService) interceptor.createProxy(); String returnValue = (String)personService.savePerson(); System.out.println(returnValue); }}Copy the code

The final run result

Final points to know:

The CGLib dynamic proxy is a jar package that needs to be included in the JDK. The CGLib dynamic proxy is a jar that needs to be included in the JDK. The CGLib dynamic proxy is a jar that needs to be included in the JDK

4. CGLib dynamic proxy is based on inheritance, so it cannot be used for final classes, private methods, and static methods

These are the two implementations of dynamic proxy.

We use the above approach to achieve the target method, realize decoupling of the code, there is no problem, but still have to generate a proxy object, handwritten interceptors, manually in the interceptor to combine to enhance the content and goals of method, it is a bit complicated to use, have a better solution?

The answer is: yes! That’s the AOP of Spring, and that’s what we’re ultimately trying to get at!

With Spring’s AOP, you don’t have to write it yourself. You just need to configure it in a configuration file. Once configured, Spring generates proxy objects for you according to your configuration, and combines the enhanced content with the target method according to your configuration. You can write your own code to achieve similar functionality to AOP, but with Spring AOP, there are some things Spring does for you, and Spring has made it configurable, very simple and flexible to use

The JDK dynamic proxy and cglib dynamic proxy are both useful in Spring AOP. Spring determines whether to use the JDK dynamic proxy to generate proxy objects or cglib to generate proxy objects, as discussed in the next article.

We’ll continue in the next article: AOP in Spring, along with pointcut expressions and various notifications

Tiezi, if you find the article helpful, you can click follow, click like

You can also pay attention to the public number: WX search: “chat 50 cents of Java”, welcome to learn to exchange, pay attention to the public number can receive the blogger’s Java learning video + material, ensure that are dry goods