当前位置:网站首页>How does cglib implement multiple agents?

How does cglib implement multiple agents?

2020-11-06 21:04:07 Java technology stack

because Cglib Own design , Can't be realized in Proxy Put another layer of packaging on the outside Proxy(JDK Proxy Sure ), The following errors are usually reported :

Caused by: java.lang.ClassFormatError: Duplicate method name "newInstance" with signature "..........  
at java.lang.ClassLoader.defineClass1(Native Method)  
at java.lang.ClassLoader.defineClass(ClassLoader.java:763)  
... 10 more  

Error source code :

net.sf.cglib.proxy.Enhancer#generateClass(ClassVisitor v)

...... Omit code   
//  The following part of the bytecode , Each generation  Proxy  Instances will be inserted .JVM  Error will be reported when verifying bytecode . 
if (useFactory || currentData != null) {  
    int[] keys = getCallbackKeys();  
    emitNewInstanceCallbacks(e);  
    emitNewInstanceCallback(e);  
    emitNewInstanceMultiarg(e, constructorInfo);  
    emitGetCallback(e, keys);  
    emitSetCallback(e, keys);  
    emitGetCallbacks(e);  
    emitSetCallbacks(e);  
}  

adopt dump The byte code is more intuitive :

In the generated bytecode ,newInstance The method is repetitive .

dump Method :System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "./");

How to deal with it ?

Implementing multiple agents , There's a lame way , for example JDK and Cglib Use a combination of . Or you can use it directly JDK agent . But sometimes , Operations on classes don't work .

I refer to Spring How to do it , A simple multi proxy is implemented .

Spring The scene of : A target method is more than one AOP Intercept , In this case, multiple agents are needed .

Spring The code to create the agent is located in :org.springframework.aop.framework.CglibAopProxy#getProxy

Spring AOP Interceptor class :org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor

Of the class intercept Method is the core of implementing multiple agents .

Every time the target method is called , According to the target method , Generate a call object with multiple intercept points of the target method .

//  Generate call object   
CglibMethodInvocation c = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy);  

//  call    
c.proceed();  

Then call the parent class proceed Method , It's actually a filter mode :

public Object proceed() throws Throwable {  
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {  
        return invokeJoinpoint();  
    }  

    Object interceptorOrInterceptionAdvice =  
            this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);  
    if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {  
        InterceptorAndDynamicMethodMatcher dm =  
                (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;  
        if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {  
            return dm.interceptor.invoke(this);  
        }  
        else {  
            // Skip this interceptor and invoke the next in the chain.  recursive .  
            return proceed();  
        }  
    }  
    else {  
        return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);  
    }  
}  

Pay attention to the last line , This is where the intercept point is called invoke Method , The specific implementation class of this intercept point :AspectJAroundAdvice.

Take a look at his invoke Method :

public Object invoke(MethodInvocation mi) throws Throwable {  
    ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;  
   // AOP  I'm familiar with it  ProceedingJoinPoint  Parameters !!!!  
    ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);  
    JoinPointMatch jpm = getJoinPointMatch(pmi);  
    return invokeAdviceMethod(pjp, jpm, null, null);  
}  

Usually , We write... In the business AOP When intercepting code , Will be exposed to this ProceedingJoinPoint Parameters , And then call him. proceed Method calls the target method .

This ProceedingJoinPoint Class proceed Method will eventually call back DynamicAdvisedInterceptor Right proceed Method . Until all intercept points are executed . Finally execute the method of the target class .

therefore , Every intercepted method you set , If this method is intercepted many times , So there's going to be multiple MethodInterceptor( No cglib Of ) Instances form call chains . And then through ProceedingJoinPoint Pass it on to you for interception .

So much bedding , Let's make a simple one ourselves , Can not be like Spring So complicated !!!!

Simple implementation Cglib Multiple agents

Let's talk about the idea first : It's actually very simple , Just put a filter chain in the interceptor , The user intercepts multiple calls in the filter . These interceptors , Just like you add @Around Method of annotation , It's just that we don't have Spring It's just convenient .

Draw a picture UML chart :

The code is as follows :

Test.java & SayHello.java

public class Test {  
  
    public static void main(String[] args) {  
        Object proxy = ProxyFactory.create().getProxy(new SayHello());  
        proxy.toString();  
    }  
  
  
    static class SayHello {  
  
        @Override  
        public String toString() {  
            return "hello cglib !";  
        }  
    }  
}  
 

ProxyFactory.java & Interceptor.java

public class ProxyFactory {  
    private ProxyFactory() {}  
    public static ProxyFactory create() {  
        return new ProxyFactory();  
    }  
    public Object getProxy(Object origin) {  
        final Enhancer en = new Enhancer();  
        en.setSuperclass(origin.getClass());  
        List<Chain.Point> list = new ArrayList<>();  
        list.add(new Point1());  
        list.add(new Point2());  
        en.setCallback(new Interceptor(new Chain(list, origin)));  
        return en.create();  
    }  
    private class Interceptor  
        implements MethodInterceptor {  
        Chain chain;  
        public Interceptor(Chain chain) {  
            this.chain = chain;  
        }  
        @Override  
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy)  
            throws Throwable {  
            return chain.proceed();  
        }  
    }  
}  
 

Chain.java & Point.java

public class Chain {  
    private List<Point> list;  
    private int index = -1;  
    private Object target;  
  
    public Chain(List<Point> list, Object target) {  
        this.list = list;  
        this.target = target;  
    }  
  
    public Object proceed() {  
        Object result;  
        if (++index == list.size()) {  
            result = (target.toString());  
            System.err.println("Target Method invoke result : " + result);  
        } else {  
            Point point = list.get(index);  
            result = point.proceed(this);  
        }  
        return result;  
    }  
    interface Point {  
        Object proceed(Chain chain);  
    }  
}  
 

Point1.java & Point2.java

public class Point1 implements Chain.Point {  
  
    @Override  
    public Object proceed(Chain chain) {  
        System.out.println("point 1 before");  
        Sleep.sleep(20);  
        Object result = chain.proceed();  
        Sleep.sleep(20);  
        System.out.println("point 1 after");  
        return result;  
    }  
}  
public class Point2 implements Chain.Point {  
  
    @Override  
    public Object proceed(Chain chain) {  
        System.out.println("point 2 before");  
        Sleep.sleep(20);  
        Object result = chain.proceed();  
        Sleep.sleep(20);  
        System.out.println("point 2 after");  
        return result;  
    }  
}  
 

function Test main result :

In line with expectations .

author : Mona · Ludao
source :https://www.cnblogs.com/stateis0/p/9744123.html Recent hot article recommends :

1.Java 15 Official release , 14 A new feature , Refresh your mind !!

2. Finally, I got it through open source projects IntelliJ IDEA Activation code , It's delicious !

3. I use Java 8 Wrote a piece of logic , I can't understand it , You try ..

4. To hang up Tomcat ,Undertow It's very powerful !!

5.《Java Development Manual ( Song Mountain version )》 The latest release , Download it quickly !

I think it's good , Don't forget to like it + Forward !

版权声明
本文为[Java technology stack]所创,转载请带上原文链接,感谢