Spring-dynamic proxy

Dynamic Proxy

Proxy pattern: Provide a proxy for other objects to control access to this object, enhance a method in a class, and extend the program.

Dynamic proxies can add additional logic to methods in a class without modifying the class source code

Creation of proxy objects through cglib:

Based on Parent and Child Classes, the proxy class is the parent class, the proxy class is the subclass, the proxy object is the instance object of the proxy class, and the proxy class is created by cglib

import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

// cglib dynamic proxy is used alone
public class Test
{
    public static void main(String[] args)
    {
        UserService target = new UserService();
        // Through cglib technology
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(UserService.class);
        // Define additional logic, that is, proxy logic
        enhancer.setCallbacks(new Callback[] {new MethodInterceptor()
        {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy)
                throws Throwable
            {
                System.out.println("before...");
// // Writing method one
// Object result = methodProxy.invoke(target, objects);

// // Writing method two
// Object result = method.invoke(target, objects);

//Writing method three
Object result = methodProxy.invokeSuper(o, objects);
                System.out.println("after...");
                return result;
            }
        }});
        // UserService object created by dynamic proxy
        UserService userService = (UserService)enhancer.create();
        //When executing the test method of this userService, some other logic will be executed.
        userService.test();
    }
}


public class UserService
{
    public void test()
    {
System.out.println("test");
    }
}

Use JDK dynamic proxy to generate a proxy object:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class Test
{
    public static void main(String[] args)
    {
        UserService target = new UserService();
        //Proxy object of UserInterface interface
        Object proxy = Proxy.newProxyInstance(UserService.class.getClassLoader(),
            new Class[] {UserInterface.class}, new InvocationHandler()
            {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args)
                    throws Throwable
                {
                    System.out.println("before...");
                    Object result = method.invoke(target, args);
                    System.out.println("after...");
                    return result;
                }
            });
// Note that this must be the interface type UserInterface. If it is the UserService class, an error will be reported.
        UserInterface userService = (UserInterface)proxy;
        userService.test();
    }
}

public class UserService implements UserInterface
{
    @Override
public void test()
    {
System.out.println("test");
    }
}

public interface UserInterface
{
public void test();
}

Note: The proxy object proxy must be of interface type

ProxyFactory

Spring encapsulates the above two dynamic proxy technologies, and the encapsulated class is called ProxyFactory

Represents a factory for creating proxy objects, which is more convenient to use.

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.framework.ProxyFactory;

public class Test
{
    public static void main(String[] args)
    {
        UserService target = new UserService();
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setTarget(target);
        proxyFactory.addAdvice(new MethodInterceptor()
        {
            @Override
            public Object invoke(MethodInvocation invocation)
                throws Throwable
            {
                System.out.println("before...");
                Object result = invocation.proceed();
                System.out.println("after...");
                return result;
            }
        });
\t\t
        UserInterface userService = (UserInterface)proxyFactory.getProxy();
        userService.test();
    }
}

public class UserService implements UserInterface
{
    @Override
public void test()
    {
System.out.println("test");
    }
}

public interface UserInterface
{
public void test();
}

ProxyFactory will automatically determine whether to use cglib or jdk dynamic proxy

If the class implements the interface, then the bottom layer of ProxyFactory will use jdk dynamic proxy

If the interface is not implemented, cglib technology will be used

Classification of Advice

1. Before Advice: executed before the method

2. After returning advice: executed after the method returns

3. After throwing advice: Execute after the method throws an exception

4. After (finally) advice: The method is executed after finally. This is the last one, later than return.

5. Around advice: This is the most powerful Advice, and the execution order can be customized.

Advisor

An Advisor consists of a Pointcut and an Advice. Pointcut can be used to specify the logic that needs to be proxied.

You can use the Advisor to control which method to proxy

public class Test
{
    public static void main(String[] args)
    {
        UserService target = new UserService();
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setTarget(target);
        proxyFactory.addAdvisor(new PointcutAdvisor()
        {
            @Override
            public Pointcut getPointcut()
            {
                return new StaticMethodMatcherPointcut()
                {
                    @Override
                    public boolean matches(Method method, Class<?> targetClass)
                    {
                        return method.getName().equals("testAbc");
                    }
                };
            }
            
            @Override
            public Advice getAdvice()
            {
                return new MethodInterceptor()
                {
                    @Override
                    public Object invoke(MethodInvocation invocation)
                        throws Throwable
                    {
                        System.out.println("before...");
                        Object result = invocation.proceed();
                        System.out.println("after...");
                        return result;
                    }
                };
            }
            
            @Override
            public boolean isPerInstance()
            {
                return false;
            }
        });
        UserInterface userService = (UserInterface)proxyFactory.getProxy();
        userService.test();
    }
}

How to create proxy objects

ProxyFactoryBean
public class UserService
{
public void test()
    {
System.out.println("test");
    }
}

@ComponentScan(value = "com.gax")
public classAppConfig
{
@Bean
    public ProxyFactoryBean userService()
    {
        UserService userService = new UserService();
        ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
        proxyFactoryBean.setTarget(userService);
        proxyFactoryBean.addAdvice(new MethodInterceptor()
        {
            @Override
            public Object invoke(MethodInvocation invocation)
                throws Throwable
            {
                System.out.println("before...");
                Object result = invocation.proceed();
                System.out.println("after...");
                return result;
            }
        });
        return proxyFactoryBean;
    }
}

public class Test
{
    public static void main(String[] args)
    {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userServiceProxy = (UserService)applicationContext.getBean("userService");
userServiceProxy.test();
}
}

The above method can only target a certain Bean

ProxyFactoryBean also has additional functions. For example, you can define an Advise or Advisor as a Bean and then set it in ProxyFactoryBean.

public class UserService
{
public void test()
    {
System.out.println("test");
    }
}

@ComponentScan(value = "com.gax")
public classAppConfig
{
@Bean
    public MethodInterceptor gaxAroundAdvise()
    {
        return new MethodInterceptor()
        {
            @Override
            public Object invoke(MethodInvocation invocation)
                throws Throwable
            {
                System.out.println("before...");
                Object result = invocation.proceed();
                System.out.println("after...");
                return result;
            }
        };
    }
    
    @Bean
    public ProxyFactoryBean userService()
    {
        UserService userService = new UserService();
        ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
        proxyFactoryBean.setTarget(userService);
        proxyFactoryBean.setInterceptorNames("gaxAroundAdvise");
        return proxyFactoryBean;
    }
}

public class Test
{
    public static void main(String[] args)
    {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userServiceProxy = (UserService)applicationContext.getBean("userService");
userServiceProxy.test();
}
}
BeanNameAutoProxyCreator

ProxyFactoryBean needs to specify the object to be proxied; BeanNameAutoProxyCreator can proxy a bean by specifying the name of the bean.

Through BeanNameAutoProxyCreator, you can perform AOP on batches of beans, and specify the proxy logic and an InterceptorName, which is an Advise. The prerequisite is that the Advise must also be a Bean so that Spring can find it. However, the shortcomings of BeanNameAutoProxyCreator are obvious. It can only specify the bean it wants to proxy based on the beanName.

@Component
public class UserService
{
public void test()
    {
System.out.println("test");
    }
}

@ComponentScan(value = "com.gax")
public classAppConfig
{
@Bean
    public MethodInterceptor gaxAroundAdvise()
    {
        return new MethodInterceptor()
        {
            @Override
            public Object invoke(MethodInvocation invocation)
                throws Throwable
            {
                System.out.println("before...");
                Object result = invocation.proceed();
                System.out.println("after...");
                return result;
            }
        };
    }
    
    @Bean
    public BeanNameAutoProxyCreator beanNameAutoProxyCreator()
    {
        BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
        beanNameAutoProxyCreator.setBeanNames("userSe*");
        beanNameAutoProxyCreator.setInterceptorNames("gaxAroundAdvise");
        beanNameAutoProxyCreator.setProxyTargetClass(true);
        return beanNameAutoProxyCreator;
    }
}

public class Test
{
    public static void main(String[] args)
    {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userServiceProxy = (UserService)applicationContext.getBean("userService");
userServiceProxy.test();
}
}
DefaultAdvisorAutoProxyCreator
@Component
public class UserService
{
public void test()
    {
System.out.println("test");
    }
}

@ComponentScan(value = "com.gax")
public classAppConfig
{
@Bean
    public MethodInterceptor gaxAroundAdvise()
    {
        return new MethodInterceptor()
        {
            @Override
            public Object invoke(MethodInvocation invocation)
                throws Throwable
            {
                System.out.println("before...");
                Object result = invocation.proceed();
                System.out.println("after...");
                return result;
            }
        };
    }
    
    @Bean
    public DefaultPointcutAdvisor defaultPointcutAdvisor()
    {
        NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
        pointcut.addMethodName("test");
        
        DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor();
        defaultPointcutAdvisor.setPointcut(pointcut);
        defaultPointcutAdvisor.setAdvice(gaxAroundAdvise());
        
        return defaultPointcutAdvisor;
    }
    
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator()
    {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        return defaultAdvisorAutoProxyCreator;
    }
}

public class Test
{
    public static void main(String[] args)
    {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userServiceProxy = (UserService)applicationContext.getBean("userService");
userServiceProxy.test();
}
}

Through DefaultAdvisorAutoProxyCreator will directly find all Advisor type beans, and determine the beans to be proxied and the proxy logic based on the PointCut and Advice information in the Advisor.

Simplified into annotation method:

@Aspect
@Component
public class GaxAspect
{
    @Before("execution(public void com.gax.service.UserService.test())")
    public void gaxBefore(JoinPoint joinPoint)
    {
        System.out.println("gaxBefore");
    }
}

Class to proxy: expression

Proxy logic: methods modified by @Before

Spring only needs to parse these annotations. After parsing, it gets the corresponding Pointcut object and Advice object, generates an Advisor object, throws it into the ProxyFactory, and then generates the corresponding proxy object. The specific way to parse these annotations is the@EnableAspectJAutoProxy annotation< /strong>Things to do

syntaxbug.com © 2021 All Rights Reserved.