@TOC #Spring collection
Record every step of the program___ auth:huf
Let us begin by defining some central AOP concepts and terminology. These terms are not Spring-specific. Unfortunately, AOP terminology is not particularly intuitive. However, it would be even more confusing if Spring used its own terminology
It means:
These concepts in AOP are not unique to Spring. Unfortunately, the concepts in AOP are not particularly intuitive, but if Spring redefines its own, it may lead to more confusion
We know; There are two kinds of proxies in Spring; One agent is JDK agent; One agent is CGLIB agent; What is the difference between the two agents? When will the JDK agent be used; Under what circumstances are post CGLIB agents used? This is something we must find out; We don't need to look at the source code in detail, no matter what is the cut-off point, what is the notification, etc; We follow the code step by step; Will understand;
CGLIB
Create a proxy class; The proxy class is the Service we often use;
To create a proxy class:
Last execution result:
All the objects obtained are CglibDemoService objects, but the effect of executing the test() method is different. This is the effect brought by the agent. The above is the creation of proxy objects through cglib, which is based on parent-child classes. The proxy class (CglibDemoService) is the parent class, the proxy class is the child class, the proxy object is the instance object of the proxy class, and the proxy class is created by cglib;
JDK agent;
JDK agent is an interface based agent; In other words, the proxy must be an interface; Then we will write an interface and an implementation;
realization:
JDK agent:
Final execution results:
The above is the main implementation of CGLIB and JDK agent;
The following code is not shown in pictures. The author hopes that readers can manually type it again. In this way, they can deepen their understanding of AOP; All the codes in this series of articles are typed out by the author one letter by one; All codes have been self tested;
ProxyFactory
In Spring; Encapsulate the above two agents; The class that encapsulates the export is called ProxyFactory, which means that it is a factory for creating proxy objects, which will be more convenient to use than the above;
package com.huf.aop; import com.huf.aop.cglib.CglibDemoService; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import org.springframework.aop.framework.ProxyFactory; /** * auth : huf */ public class ProxyFactoryDemo { public static void main(String[] args) { CglibDemoService target = new CglibDemoService(); ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.setTarget(target); proxyFactory.addAdvice(new MethodInterceptor() { @Override public Object invoke(MethodInvocation methodInvocation) throws Throwable { System.out.println("Before executing the method : before"); Object result = methodInvocation.proceed(); System.out.println("Before executing the method : after"); return result; } }); CglibDemoService cglibDemoService = (CglibDemoService) proxyFactory.getProxy(); cglibDemoService.test(); } }
Through ProxyFactory, we can no longer decide whether to use cglib or jdk dynamic proxy. ProxyFactory will help us judge
If the class we put in setTarget() implements the interface, ProxyFactory will select JDK proxy. If it is not the interface, CGLIB proxy will be used; The above is the CGLIB agent used; If it is replaced with JdkDemoService, it is the JDK agent, so the converted JdkDemoInterface;
In the Proxy class above, we see that we have added an Advice, where Advice is our < < notification > >
Classification of Advice
- Before Advice: execute before method
- After returning advice: the method is executed after return
- After throwing advice: the method executes after throwing an exception
- After (finally) advice: the method is executed after it is finally executed. This is the last, which is later than return
- Around advice: This is the most powerful Advice. You can customize the execution order
Advisor
In my personal understanding, Advisor is an enhancement of Advice; An Advisor contains
An Advice – < < notification > >
A Pointcut – < tangent point > >
The logic to be represented can be specified through Pointcut;
A small case can clearly know what Pointcut is
/** * auth : huf */ public class ProxyFactoryDemo { public static void main(String[] args) { JdkDemoService jdkDemoService = new JdkDemoService(); ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.setTarget(jdkDemoService); proxyFactory.addAdvisor(new PointcutAdvisor() { Which method does the pointcut cut cut into; @Override public Pointcut getPointcut() { return new StaticMethodMatcherPointcut() { @Override public boolean matches(Method method, Class<?> aClass) { return method.getName().equals("test1"); } }; } @Override public Advice getAdvice() { return new MethodInterceptor() { @Override public Object invoke(MethodInvocation methodInvocation) throws Throwable { System.out.println("Before method execution : before"); Object proceed = methodInvocation.proceed(); System.out.println("After method execution : after"); return proceed; } }; } @Override public boolean isPerInstance() { return false; } }); JdkDemoInterface jdkDemoInterface = (JdkDemoInterface) proxyFactory.getProxy(); In execution test Method of; Will not be represented; Because there's one jdkDemoInterface.test(); System.out.println("------------------------------------------------------------"); In execution test1 The method is represented; jdkDemoInterface.test1(); } }
How proxy objects are created
As described above, Spring provides [ProxyFactory, Advisor, Advice, PointCut] and other technologies to create proxy objects. However, when we use Spring, we do not directly use ProxyFactory. For example, we hope that the proxy object generated by ProxyFactory can be a Bean directly, and the proxy object of UserSerivce can be obtained directly from the Spring container, As developers, we must tell Spring which classes need to be proxied and what the proxy logic is
The following is an evolutionary process; We will gradually go deep into AOP;
We register beans through ProxyBean;
ProxyFactoryBean
@Bean public ProxyFactoryBean proxyFactoryBean() { CglibDemoService cglibDemoService = new CglibDemoService(); ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean(); proxyFactoryBean.setTarget(cglibDemoService); proxyFactoryBean.addAdvice(new MethodInterceptor() { @Override public Object invoke(MethodInvocation methodInvocation) throws Throwable { System.out.println("Before method execution : before"); Object proceed = methodInvocation.proceed(); System.out.println("After method execution : after"); return proceed; } }); return proxyFactoryBean; }
The results are:
Continue to evolve; We can register advice separately;
@Bean public MethodInterceptor hufAroundAdvise() { return new MethodInterceptor() { @Override public Object invoke(MethodInvocation invocation) throws Throwable { System.out.println("Before method execution : before"); Object proceed = invocation.proceed(); System.out.println("After method execution : after"); return proceed; } }; } @Bean public ProxyFactoryBean proxyFactoryBean() { CglibDemoService cglibDemoService = new CglibDemoService(); ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean(); proxyFactoryBean.setTarget(cglibDemoService); proxyFactoryBean.setInterceptorNames("hufAroundAdvise"); return proxyFactoryBean; }
Their execution results are as like as two peas, only advice is registered as Bean.
Continue to dig deep; Since we can register one, can we register in batches??
BeanNameAutoProxyCreator
Two ordinary Service @Component public class CglibDemoService { public void test(){ System.out.println("CGLIB Dynamic proxy demo;"); } } @Component public class CglibDemoService2 { public void test(){ System.out.println("CGLIB2 Dynamic proxy demo;"); } }
@Configuration public class AopConfig { @Bean public MethodInterceptor hufAroundAdvise() { return new MethodInterceptor() { @Override public Object invoke(MethodInvocation invocation) throws Throwable { System.out.println("Before method execution : before"); Object proceed = invocation.proceed(); System.out.println("After method execution : after"); return proceed; } }; } @Bean public BeanNameAutoProxyCreator beanNameAutoProxyCreator() { BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator(); beanNameAutoProxyCreator.setBeanNames("cglibDemoServic*"); beanNameAutoProxyCreator.setInterceptorNames("hufAroundAdvise"); beanNameAutoProxyCreator.setProxyTargetClass(true); return beanNameAutoProxyCreator; } }
Execution:
result:
Although this method is feasible, it can only be represented by Class Name to continue to dig deeper
DefaultAdvisorAutoProxyCreator
@Bean public MethodInterceptor hufAroundAdvise() { return new MethodInterceptor() { @Override public Object invoke(MethodInvocation invocation) throws Throwable { System.out.println("Before method execution : before ...."); Object proceed = invocation.proceed(); System.out.println("After method execution : after...."); return proceed; } }; } @Bean public DefaultPointcutAdvisor defaultPointcutAdvisor(MethodInterceptor hufAroundAdvise){ NameMatchMethodPointcut nameMatchMethodPointcut = new NameMatchMethodPointcut(); nameMatchMethodPointcut.addMethodName("test"); //Name of the method to cut in DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor(); defaultPointcutAdvisor.setPointcut(nameMatchMethodPointcut);//Injection tangent defaultPointcutAdvisor.setAdvice(hufAroundAdvise);//Injection pointcut logic return defaultPointcutAdvisor; } @Bean public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){ DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); return defaultAdvisorAutoProxyCreator; }
The defaultadvisor autoproxycreator will directly find all Advisor type beans, and determine the beans to be proxied and the proxy logic according to the PointCut and Advice information in the Advisor
In this way, we register all beans in this chapter into the container; Bean s including JDK agents are also registered;
Execution:
Implementation results obtained:
In this way, we have a deeper evolution;
Summary:
This chapter explains
- Implementation of CGLIB
- Implementation of JDK dynamic agent;
The of AOP is introduced - Pointcut - tangent point
- Advice - Notification
- Advisor - combination of the first two;
This paper introduces entity classes - ProxyFactory - used by Spring
- ProxyFactoryBean -- register into the Spring container to generate a single bean
- BeanNameAutoProxyCreator – mass produce proxy objects by class name
- Defaultadvisor autoproxycreator – mass produce proxy objects by method name
The next chapter will explain the source code of AOP; AOP itself is not difficult, so its source code is simpler than the previous articles; And have a foreshadowing of this article; It can be said to take off directly;