[Spring] proxy mode -- dynamic proxy

Posted by ojsimon on Wed, 15 Dec 2021 18:22:58 +0100

Agent mode -- dynamic agent

Static proxy: the proxy class must exist,
Dynamic agent: when the program is running, the agent class is dynamically generated according to the object to be represented.
Type: 1. Dynamic agent based on JDK
2. Dynamic agent based on CGLIB

1 dynamic agent based on JDK


Static, directly using Proxy call
newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
ClassLoader: class loader, because of the dynamic proxy class, with the help of others' class loader. Generally, the proxy object is used
Class loader.
Class[] interfaces: the collection of interface class objects, the proxy for the interface, and which interface is used as the proxy. It is generally used
Is the interface of the proxy object.
InvocationHandler: handle, callback function, write the rule code of the agent

public Object invoke(Object arg0, Method arg1, Object[] arg2)
Object arg0: proxy object
Method arg1: proxy method
Object[] arg2: array of parameters when the proxy method is executed

public class MyJDKProxy { 
public static void main(String[] args) { 
    //Target object -- proxied object 
    TeamService teamService=new TeamService(); 
    //Return proxy object 
    //Call the static method newProxyInstance in the Proxy class in the JDK to get the instance of the dynamic Proxy class 
    IService proxyService= (IService) Proxy.newProxyInstance( 
        teamService.getClass().getClassLoader(), 
        teamService.getClass().getInterfaces(), 
        new InvocationHandler() {
            //Write proxy rules for callback functions 
            @Override 
            public Object invoke(Object proxy, Method method, Object[] 
                args) throws Throwable { 
                try { 
                    System.out.println("Start transaction"); 
                    //core business  
                    Object invoke = method.invoke(teamService, args); 
                    System.out.println("Commit transaction"); 
                    return invoke;
                }catch (Exception e){ 
                    System.out.println("Rollback transaction"); 
                    e.printStackTrace(); 
                    throw e; 
                }finally { 
                    System.out.println("finally---------"); 
                } 
            } 
        } 
    ); 
    //Proxy object 
    proxyService.add(); 
    System.out.println(teamService.getClass()); 
    System.out.println(proxyService.getClass()+"--------"); 
}
}

2 structured design

Mode 1:

public class ProxyHandler implements InvocationHandler { 
    private IService service;//Target object 
    private AOP aop;//section 
    public ProxyHandler(IService service, AOP aop) { 
        this.service = service; 
        this.aop = aop; 
    }
    @Override 
    public Object invoke(Object proxy, Method method, Object[] 
    args) throws Throwable { 
        try { 
            aop.before(); 
            Object invoke = method.invoke(service, args);//core business  
            aop.after(); return invoke; 
        }catch (Exception e){ 
            aop.exception(); 
            e.printStackTrace(); 
            throw e; 
        }finally { 
            aop.myFinally(); 
        } 
    } 
}
public static void main2(String[] args) { 
    //Target object -- proxied object 
    TeamService teamService=new TeamService(); 
    //section 
    AOP tranAop=new TranAOP(); 
    //Return proxy object JDK based dynamic proxy 
    IService proxyService= (IService) Proxy.newProxyInstance( 
        teamService.getClass().getClassLoader(), 
        teamService.getClass().getInterfaces(), 
        new ProxyHandler(teamService,tranAop) 
    ); 
    //Proxy object 
    proxyService.add(); 
    System.out.println(teamService.getClass()
    System.out.println(proxyService.getClass()+"------"); 
}

Mode 2:

public class ProxyFactory { 
    private IService service;//Target object 
    private AOP aop;//section 
    public ProxyFactory(IService service, AOP aop) { 
        this.service = service; 
        this.aop = aop; 
    } 
    /** 
     * Get an example of a dynamic proxy 
    * @return 
    */ 
    public Object getProxyInstance() { 
        return Proxy.newProxyInstance( 
            service.getClass().getClassLoader(), 
            service.getClass().getInterfaces(), 
            new InvocationHandler() {
                //Write proxy rules for callback functions 
                @Override 
                public Object invoke(Object proxy, Method method, Object[] 
                    args) throws Throwable { 
                    try { 
                        aop.before();
                        //core business   
                        Object invoke = method.invoke(service, args);
                        aop.after(); 
                        return invoke; 
                    }catch (Exception e){ 
                        aop.exception(); 
                        e.printStackTrace(); 
                        throw e; 
                    }finally { 
                        aop.myFinally(); 
                    } 
                } 
            } 
        ); 
    } 
}
public static void main(String[] args) { 
    //Target object -- proxied object 
    TeamService teamService=new TeamService(); 
    //section 
    AOP tranAop=new TranAOP(); 
    AOP logAop=new LogAop(); 
    //Get proxy object 
    IService service= (IService) new 
    ProxyFactory(teamService,tranAop).getProxyInstance(); 
        IService service1= (IService) new 
    ProxyFactory(service,logAop).getProxyInstance(); //Secondary agent
    service1.add();
    //The core business + service code is a complete business method mixed together 
}

The proxy object does not need to implement the interface, but the target object must implement the interface; Otherwise, you cannot use JDK dynamic proxy. If you want to extend the function,
But the target object does not implement the interface. How to extend the function?
Subclass to implement the proxy CGLIB.

3 dynamic agent based on CGLIB

Cglib proxy, also known as subclass proxy. Build a subclass object in memory to expand the function of the target object.
One limitation of dynamic proxy in JDK is that objects using dynamic proxy must implement one or more interfaces. If you want to proxy a class that does not implement an interface, you can use CGLIB implementation.
CGLIB is a powerful high-performance code generation package, which can extend Java classes and implement Java interfaces at run time. It is widely used by many AOP frameworks, such as Spring AOP and dynaop, to provide them with method interception.
The bottom layer of CGLIB package is to convert bytecode and generate new classes by using a small and fast bytecode processing framework ASM. Direct use of ASM is discouraged because it requires you to be familiar with the internal structure of the JVM, including the format of class files and instruction sets.

3.1 testing

public class NBAService { 
    public int add(String name,int id){ 
        System.out.println("NBAService---- add----"); 
        return id; 
    } 
}
public static void main(String[] args) { 
    //Target object: no interface 
    NBAService nbaService=new NBAService(); 
    //Create proxy object: select cglib dynamic proxy 
    NBAService proxyService= (NBAService) Enhancer.create(
        nbaService.getClass(), 
        new MethodInterceptor() {
            //Write proxy rules for callback functions 
            @Override 
           public Object intercept(Object o, Method method, 
           Object[] objects, MethodProxy methodProxy) throws Throwable { 
                try { 
                    System.out.println("Start transaction"); 
                     //core 
                    Object invoke = methodProxy.invokeSuper(o, objects);
                    System.out.println("Commit transaction"); 
                    return invoke; 
                }catch (Exception e){ 
                    System.out.println("Transaction rollback"); 
                    throw e; 
                }finally { 
                    System.out.println("finally------------"); 
                } 
            } 
        }
    ); 
    //Proxy object 
    int res=proxyService.add("huren",1001); 
    System.out.println(res); 
}

3.2 structured design method

public class CglibProxyFactory { 
    //Target object
    private NBAService nbaService;//No interface implemented 
    //section 
    private AOP aop; 
    /** 
     * Create proxy object 
     * @param nbaService 
     * @param aop 
    * @return 
    */ 
    public Object getProxyInstance(NBAService nbaService,AOP aop){
        return Enhancer.create(nbaService.getClass(), 
        new MethodInterceptor() {
            //Write proxy rules for callback functions 
            @Override 
            public Object intercept(Object o, Method method, 
            Object[] objects, MethodProxy methodProxy) throws Throwable { 
                try { 
                    aop.before(); 
                    Object o1 = methodProxy.invokeSuper(o, objects); 
                    aop.after(); 
                    return o1; 
                }catch (Exception e){ 
                    aop.exception(); 
                    throw e; 
                } finally { 
                    System.out.println("finally-----------"); 
                } 
            } 
        }
        );
    }
}
public static void main(String[] args) { 
    //Target object: no interface 
    NBAService nbaService=new NBAService(); 
    //Create slice 
    AOP tranAop=new TranAOP(); 
    //Create proxy object: select cglib dynamic proxy 
    NBAService proxyInstance = (NBAService) 
        new CglibProxyFactory().getProxyInstance(nbaService, tranAop); 
    int res=proxyInstance.add("huren",1001); 
    System.out.println(res); 
}

Topics: Java Spring Design Pattern SSM