Location>code7788 >text

Design Patterns of cglib Dynamic Proxy

Popularity:684 ℃/2024-08-20 14:18:04

What is a dynamic agent?
Dynamic proxy is in the java process runtime, through the bytecode technology, dynamically generate a proxy class of a class. In this proxy class, we can do some additional operations, on the one hand, still maintain the original method of the ability, on the other hand, but also enhance these capabilities. Listen is not AOP is a bit like, yes, dynamic proxy is the technical cornerstone of AOP.
I had written two related articles before this one:
/jilodream/p/ Design Patterns of Proxy Patterns
/jilodream/p/ Design Patterns of Jdk Dynamic Proxy

And when implementing dynamic proxies, there are generally two approaches:
jdk dynamic agent (which you can check out by clicking the link above), and the cglib dynamic agent.
Without further ado, let's look at how to use cglib for dynamic proxying:

Example we still use the same star/star proxy class as the jdk dynamic proxy for this scenario
celebrity category

 1 package ;
 2 
 3 import ;
 4 import ;
 5 
 6 /**
 7  * @discription
 8  */
 9 
10 @Data
11 @NoArgsConstructor
12 public class SuperStar implements ISuperStar {
13     String starName;
14 
15     public SuperStar(String starName) {
16         this.starName = starName;
17     }
18 
19     @Override
20     public void signContract() {
21         (starName + " Signature.");
22         // to do sth
23         return;
24     }
25 
26     @Override
27     public void negotiate() {
28         (starName + " Negotiation ");
29         // to do sth
30         return;
31     }
32 
33     @Override
34     public String getStarImage() {
35         (starName + " start image");
36         // to do sth
37         return "One " + starName + " Image";
38     }
39 }

star class interface

 1 package ;
 2 
 3 public interface ISuperStar
 4 {
 5     /**
 6      * :: Signing
 7      */
 8     void signContract();
 9 
10     void negotiate();
11 
12     String getStarImage();
13 }

Agent Factory

 1 package ;
 2 
 3 
 4 import ;
 5 import ;
 6 import ;
 7 import ;
 8 
 9 import ;
10 
11 /**
12  * @discription
13  */
14 public class ProxyFactory implements MethodInterceptor {
15 
16     private String starName;
17 
18     public SuperStar create(String starName) {
19         (DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "E:\\code\\common\\learn-design" +
20                 "-pattern\\target\\cglib");
21 
22         this.starName = starName;
23         Enhancer enhancer = new Enhancer();
24         (SuperStar.class);
25         (this);
26         SuperStar proxy = (SuperStar) ();
27          = starName;
28         return proxy;
29     }
30 
31 
32     @Override
33     public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
34         (starName + "agents began organizing activities.");
35         Object obj = (o, objects);
36         (starName + "the end of the organization's activities by its agents".);
37         return obj;
38     }
39 }

main category

 1 package ;
 2 
 3 /**
 4  * @discription
 5  */
 6 public class CglibMain {
 7     public static void main(String[] args) {
 8         ProxyFactory factory = new ProxyFactory();
 9         SuperStar superStar = ("messi");
10         ();
11         ();
12         String image=();
13         ("we get a image: "+image);
14     }
15 
16 
17 }

operational effect

messi's agents start organizing events
messi Signature
Agents of messi end organization activities
messi's agent starts organizing
messi Negotiation
messi's agent ends organization
messi's agent starts organizing activities
messi start image
Messi's agent ends organizing activities
we get an image: One messi Image
Disconnected from the target VM, address.'127.0.0.1:64165', transport: 'socket'

The core logic for generating proxy classes is in the #create method:

We start by declaring an enhancer: Enhancer enhancer
Next, set the proxy class parent: already
Next set up the callback class (the class that contains the augmented method): ? implements MethodInterceptor
The final call to the create method of the augmented class is generated:()

The overall process is much like that of the jdk dynamic agent, the

The difference is that jdk dynamic proxy is based on the interface, dynamically generated implementation of the class , the proxy class and the proxy class are interface implementation class , is a "brotherhood", the proxy method is the interface in the open method.
The cglib dynamic proxy is to take the proxied class as the parent class and derive subclasses, the proxied class and the proxied class are inheritance relationship, it is the "parent-child relationship", the proxied methods are the public methods in the parent class.
Below:

 

In fact, think about it is very normal, we want to indirectly and dynamically access to the public methods of a class, there are two ways, the first is inherited from it, then all its public methods we can continue to hold (cglib thinking). The second is to implement the same conventions (interfaces) with him, then it has more developed protocols, we can also dynamically get to the (jdk dynamic proxy ideas).

Having said that to talk about the limitations of the cglib approach, it is mainly related to inheritance:
1, can not dynamically proxy final method, because the subclass can not be rewritten.

2, can not dynamically proxy static, because the subclass can not be rewritten.
jdk dynamic proxy and cglib can be said to have their own advantages and disadvantages, many people say that after the speed of the jdk dynamic proxy optimization, spring has been used by default jdk dynamic proxy.

Let me make two points here.

1, the design and implementation are two different things, the future cglib implementation of ideas after optimization, and won, it does not mean that the cglib design solution is better;

2, the latest version of Springboot and the use of cglib as the default aop implementation, which does not mean that cglib than the jdk dynamic proxy way to be strong.


ps: If you want to save the dynamically generated class file to disk at runtime, you can add it in the code out of the execution, as shown in the red font in the code example above:
(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "E:\\code\\common\\learn-design-pattern\\target\\cglib");