Author: Little Fu Ge blog: https://bugstack.cn

Precipitate, share, grow, let oneself and others can have a harvest! 😄

One, foreword

Garson, this code is too deep for you to handle!

In the TV drama “Legend of Chu and Han”, there is such a conversation between Liu Bang and Han Xin over drinking. Liu Bang asks Han Xin how many soldiers can Cao Can take after he has read books and seen the world. Han Xin says that he can take fifteen thousand soldiers, and adds that fifteen thousand soldiers are difficult. Liu Bang mentioned Fan Kuai, Lu Wan, and Zhou Bo, Han Xin said with a smile, “Less than twenty thousand kuai, my brain doesn’t work well.” At this time, Liu Bang was a little embarrassed and asked: What about me? How many soldiers can I bring? Han Xin said, “You can take 100,000.” Liu Bang looked more than them, ah, ok. Then he asked Han Xin how about you? How many soldiers can you bring? Han Xin had too much to drink. Go on, me, me, the more the better. At this time Liu Bang vexed leadership strength to come up, ask: that I why ability tube you, you say to me, say!


Isn’t it like your boss asking you how much code you can write, how many frameworks you can build, and how many projects you can take on? It is possible that a large part of new code farmers without too much experience can only complete the development of some simple functional modules, but they cannot control all the projects involved in the whole project, nor can they extract some reusable universal component modules for the project. In the primary code farmer’s heart, pick up a bit of demand is good, but no one with the time to completely pick up a larger project will be more panic, do not know whether there is a pit here, oneself also grasp not. These pieces of code can be written in pieces, but getting them all is hard!

On the road of code development and growth, I have to go through CRUD, ERP data checking, interface packaging, function development, service integration, system construction, etc., until I independently lead people to undertake the construction of larger projects. This process requires you to have a lot of experience writing code and dealing with complex problems before you can assemble seemingly independent modules and snippets of code into a larger, running project. As with Spring, we are always adding new feature pieces and finally integrating the technology implementation with the Spring container to make it easier for users to take advantage of the capabilities Spring provides.

Second, the target

In the previous section we did our own custom processing of matched objects by handling method matching and method interception in the proxy. newProxyInstance Proxy operation. By undoing this technical core into Spring to implement the AOP part, you can basically define the responsibilities of each class, including your proxy target object properties, interceptor properties, method matching properties, and how the two different proxies operate the JDK and CGlib.

With an AOP core functionality implemented, we can intercept methods by verifying the aspect functionality in a unit testing manner, but if it is a user-oriented functionality, it is unlikely that users will be able to use AOP alone in such a complex way that it is not integrated with Spring. But the use of the past or dispersed.

Therefore, we need to complete the integration of AOP core functions with the Spring framework in this section, and finally complete the operation of aspects in the way of Spring configuration.

Three,

  1. Since BeanPostProcessor, let in XML configuration is loaded into the DefaultAdvisorAutoProxyCreator implementation,
  2. In fact, once the core features are developed, this is not difficult. We just have to solve a few problems, including how to concatenate the Bean lifecycle, how to assemble the functions, how to adapt the proxy,
  3. Dynamic proxies are integrated into the Bean life cycle through the BeanPostProcessor

In fact, with the implementation of the core FUNCTIONALITY of AOP, it is not difficult to integrate these functions and services into Spring, but to solve several problems, including: How to integrate dynamic proxies into the Bean lifecycle through BeanPostProcessor, and how to assemble pointcuts, interceptors, and prefixes, and adapt the corresponding proxies. The overall design structure is as follows:

  • In order for the proxy objects configured in XML to be instantiated during object creation, i.e., some class objects of the aspect, we need to use the methods provided by BeanPostProcessor, because the methods in this class can be used to modify the extension information of the Bean object before and after the Bean object is initialized. But the new interface and implementation class need to be implemented in BeanPostProcessor so that the corresponding class information can be directed.
  • Before but because create a proxy object is not the ordinary objects in the process, so we need before on other objects to create, so in the actual development process, the need to AbstractAutowireCapableBeanFactory# createBean prioritize Bean object judgment, If a proxy is required, return the proxy object directly.The createBean and doCreateBean methods are split in the Spring source code
  • This section also includes the specific functions to resolve the interceptors, providing some BeforeAdvice and AfterAdvice implementations to make it easier for users to use the aspect functions. This includes the need to wrap aspect expressions and the integration of interception methods, as well as agent factories that provide different types of proxy methods to wrap our aspect services.

Four, implementation,

1. Engineering structure

Small - spring - step - 12 └ ─ ─ the SRC ├ ─ ─ the main │ └ ─ ─ Java │ └ ─ ─ cn. Bugstack. Springframework │ ├ ─ ─ aop │ │ ├ ─ ─ aspectj │ │ │ └ ─ ─ AspectJExpressionPointcut. Java │ │ │ └ ─ ─ AspectJExpressionPointcutAdvisor. Java │ │ ├ ─ ─ framework │ │ │ ├ ─ ─ adapter │ │ │ │ └ ─ ─ MethodBeforeAdviceInterceptor. Java │ │ │ ├ ─ ─ autoproxy │ │ │ │ └ ─ ─ MethodBeforeAdviceInterceptor. Java │ │ │ ├ ─ ─ │ ├─ bass exercises. ├─ Bass exercises. ├─ Bass exercises. ├─ Bass exercises. ├─ Bass exercises ReflectiveMethodInvocation. Java │ │ ├ ─ ─ AdvisedSupport. Java │ │ ├ ─ ─ Advisor. Java │ │ ├ ─ ─ BeforeAdvice. Java │ │ ├ ─ ─ Classfilter.java │ ├── MethodBeforeadvice.java │ ├─ ├─ MethodMatcher.java │ ├─ Pointcut │ ├── exercises │ ├─ Exercises │ ├─ Exercises │ ├─ exercises │ ├─ Exercises │ ├─ Exercises │ ├─ Exercises AutowireCapableBeanFactory. Java │ │ │ │ ├ ─ ─ BeanDefinition. Java │ │ │ │ ├ ─ ─ spring BeanFactoryPostProcessor. Java │ │ │ │ ├ ─ ─ BeanPostProcessor. Java │ │ │ │ ├ ─ ─ BeanReference. Java │ │ │ │ ├ ─ ─ ConfigurableBeanFactory. Java │ │ │ │ ├ ─ ─ InstantiationAwareBeanPostProcessor. Java │ │ │ │ └ ─ ─ SingletonBeanRegistry. Java │ │ │ ├ ─ ─ support │ │ │ │ ├ ─ ─ AbstractAutowireCapableBeanFactory. Java │ │ │ │ ├ ─ ─ AbstractBeanDefinitionReader. Java │ │ │ │ ├ ─ ─ AbstractBeanFactory. Java │ │ │ │ ├ ─ ─ BeanDefinitionReader. Java │ │ │ │ ├ ─ ─ BeanDefinitionRegistry. Java │ │ │ │ ├ ─ ─ CglibSubclassingInstantiationStrategy. Java │ │ │ │ ├ ─ ─ DefaultListableBeanFactory. Java │ │ │ │ ├ ─ ─ DefaultSingletonBeanRegistry. Java │ │ │ │ ├ ─ ─ DisposableBeanAdapter. Java │ │ │ │ ├ ─ ─ FactoryBeanRegistrySupport. Java │ │ │ │ ├ ─ ─ InstantiationStrategy. Java │ │ │ │ └ ─ ─ SimpleInstantiationStrategy. Java │ │ │ ├ ─ ─ support │ │ │ │ └ ─ ─ XmlBeanDefinitionReader. Java │ │ │ ├ ─ ─ Aware. Java │ │ │ ├ ─ ─ BeanClassLoaderAware. Java │ │ │ ├ ─ ─ the BeanFactory. Java │ │ │ ├ ─ ─ BeanFactoryAware. Java │ │ │ ├ ─ ─ BeanNameAware. Java │ │ │ ├ ─ ─ ConfigurableListableBeanFactory. Java │ │ │ ├ ─ ─ DisposableBean. Java │ │ │ ├ ─ ─ FactoryBean. Java │ │ │ ├ ─ ─ HierarchicalBeanFactory. Java │ │ │ ├ ─ ─ InitializingBean. Java │ │ ├─ ├─ class.htm │ ├─ class.htm │ ├─ Class.htm │ ├─ Class.htm │ ├─ Class.htm │ ├─ Class.htm │ ├─ Class.htm │ ├─ Class.htm │ ├─ Class.htm │ ├─ Class.htm │ ├─ Class.htm ├ ─ ─ the context │ │ ├ ─ ─ event │ │ │ ├ ─ ─ AbstractApplicationEventMulticaster. Java │ │ │ ├ ─ ─ ApplicationContextEvent. Java │ │ │ ├ ─ ─ ApplicationEventMulticaster. Java │ │ │ ├ ─ ─ ContextClosedEvent. Java │ │ │ ├ ─ ─ ContextRefreshedEvent. Java │ │ │ └ ─ ─ SimpleApplicationEventMulticaster. Java │ │ ├ ─ ─ support │ │ │ ├ ─ ─ AbstractApplicationContext. Java │ │ │ ├ ─ ─ AbstractRefreshableApplicationContext. Java │ │ │ ├ ─ ─ AbstractXmlApplicationContext. Java │ │ │ ├ ─ ─ ApplicationContextAwareProcessor. Java │ │ │ └ ─ ─ ClassPathXmlApplicationContext. Java │ │ ├ ─ ─ ApplicationContext. Java │ │ ├ ─ ─ ApplicationContextAware. Java │ │ ├ ─ ─ ApplicationEvent. Java │ │ ├ ─ ─ ApplicationEventPublisher. Java │ │ ├ ─ ─ ApplicationListener. Java │ │ └ ─ ─ ConfigurableApplicationContext. Java │ ├ ─ ─ core. IO │ │ ├ ─ ─ ClassPathResource. Java │ │ ├ ─ ─ DefaultResourceLoader. Java │ │ ├ ─ ─ FileSystemResource. Java │ │ ├ ─ ─ the Resource. The Java │ │ ├ ─ ─ ResourceLoader. Java │ │ └ ─ ─ UrlResource. Java │ └ ─ ─ utils │ └ ─ ─ ClassUtils. Java └ ─ ─ the test └ ─ ─ Java └ ─ ─ cn. Bugstack. Springframework. Test ├ ─ ─ bean │ ├ ─ ─ IUserService. Java │ ├ ─ ─ UserService. Java │ └ ─ ─ UserServiceInterceptor. Java └ ─ ─ ApiTest. Java

Project source code: public number “bugstack wormhole stack”, reply: Spring column, obtain complete source code

AOP dynamic proxy fits into the class relationships in the Bean lifecycle, as shown in Figure 13-2

  • The whole class diagram you can see, in the BeanPostProcessor interface implementation inheritance InstantiationAwareBeanPostProcessor interface, Made a DefaultAdvisorAutoProxyCreator automatic proxy created class, this class is used to process the AOP agent into the Bean in the lifecycle of a core class.
  • DefaultAdvisorAutoProxyCreator will depend on the interceptor, agent factory and Pointcut and Advisor AspectJExpressionPointcutAdvisor packaging services, provided by its tangent plane, intercept method, and expression.
  • Spring AOP refines Advice with BeforeAdvice, AfterAdvice, AfterReturningAdvice, and ThrowsAdvice. So far we only use BeforeAdvice in our test cases. This section can be supplemented by testing against Spring source code.

2. Define the Advice interceptor chain

cn.bugstack.springframework.aop.BeforeAdvice

public interface BeforeAdvice extends Advice {

}

cn.bugstack.springframework.aop.MethodBeforeAdvice

public interface MethodBeforeAdvice extends BeforeAdvice { /** * Callback before a given method is invoked. * * @param method method being invoked * @param args arguments to the method * @param target target of the method invocation. May be <code>null</code>. * @throws Throwable if this object wishes to abort the call. * Any exception thrown will be returned to the caller if it's * allowed by the method signature. Otherwise the exception * will be wrapped as a runtime  exception. */ void before(Method method, Object[] args, Object target) throws Throwable; }
  • In the Spring framework, Advice is implemented through the MethodInterceptor MethodInterceptor. Wrapping Advice is similar to an interceptor link, BeforeAdvice, After Advice, etc., but for the time being we need that much so we only define a MethodBeforeAdvice interface definition.

3. Define the Advisor visitor

cn.bugstack.springframework.aop.Advisor

public interface Advisor { /** * Return the advice part of this aspect. An advice may be an * interceptor, a before advice, a throws advice, etc. * @return the advice that should apply if the pointcut matches * @see org.aopalliance.intercept.MethodInterceptor *  @see BeforeAdvice */ Advice getAdvice(); }

cn.bugstack.springframework.aop.PointcutAdvisor

public interface PointcutAdvisor extends Advisor {

    /**
     * Get the Pointcut that drives this advisor.
     */
    Pointcut getPointcut();

}
  • The Advisor takes on a combination of the Pointcut that gets the JoinPoint and the Advice that determines what the JoinPoint does.

cn.bugstack.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor

Public class AspectJExpressionPointcutAdvisor implements PointcutAdvisor {/ / section private AspectJExpressionPointcut pointcut; Private Advice Advice; // Private String expression; public void setExpression(String expression){ this.expression = expression; } @Override public Pointcut getPointcut() { if (null == pointcut) { pointcut = new AspectJExpressionPointcut(expression); } return pointcut; } @Override public Advice getAdvice() { return advice; } public void setAdvice(Advice advice){ this.advice = advice; }}
  • AspectJExpressionPointcutAdvisor PointcutAdvisor interface is achieved, the plane pointcut, intercept method advice and intercept the expression of specific packaging together. This enables you to define a pointcutAdvisor aspect interceptor in the XML configuration.

4. Method interceptor

cn.bugstack.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor

public class MethodBeforeAdviceInterceptor implements MethodInterceptor { private MethodBeforeAdvice advice; public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) { this.advice = advice; } @Override public Object invoke(MethodInvocation methodInvocation) throws Throwable { this.advice.before(methodInvocation.getMethod(), methodInvocation.getArguments(), methodInvocation.getThis()); return methodInvocation.proceed(); }}
  • MethodBeforeAdviceInterceptor implements the MethodInterceptor interfaces, invoked in the invoke method before method in the advice, information was introduced into the corresponding parameters.
  • The advice.before is used to implement the MethodBeforeAdvice interface yourself.You can see that the actual implementation of the MethodInterceptor class is the same as we did before, except that Spring now handles it

5. Agent factory

cn.bugstack.springframework.aop.framework.ProxyFactory

public class ProxyFactory { private AdvisedSupport advisedSupport; public ProxyFactory(AdvisedSupport advisedSupport) { this.advisedSupport = advisedSupport; } public Object getProxy() { return createAopProxy().getProxy(); } private AopProxy createAopProxy() { if (advisedSupport.isProxyTargetClass()) { return new Cglib2AopProxy(advisedSupport); } return new JdkDynamicAopProxy(advisedSupport); }}
  • In fact, the agent factory solves the problem of choosing the JDK and Cglib agents, which can be controlled according to different creation requirements.

6. Automatic agent creator that fits into the Bean lifecycle

cn.bugstack.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator

public class DefaultAdvisorAutoProxyCreator implements InstantiationAwareBeanPostProcessor, BeanFactoryAware { private DefaultListableBeanFactory beanFactory; @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { this.beanFactory = (DefaultListableBeanFactory) beanFactory; } @Override public Object postProcessBeforeInstantiation(Class<? > beanClass, String beanName) throws BeansException { if (isInfrastructureClass(beanClass)) return null; Collection<AspectJExpressionPointcutAdvisor> advisors = beanFactory.getBeansOfType(AspectJExpressionPointcutAdvisor.class).values(); for (AspectJExpressionPointcutAdvisor advisor : advisors) { ClassFilter classFilter = advisor.getPointcut().getClassFilter(); if (! classFilter.matches(beanClass)) continue; AdvisedSupport advisedSupport = new AdvisedSupport(); TargetSource targetSource = null; try { targetSource = new TargetSource(beanClass.getDeclaredConstructor().newInstance()); } catch (Exception e) { e.printStackTrace(); } advisedSupport.setTargetSource(targetSource); advisedSupport.setMethodInterceptor((MethodInterceptor) advisor.getAdvice()); advisedSupport.setMethodMatcher(advisor.getPointcut().getMethodMatcher()); advisedSupport.setProxyTargetClass(false); return new ProxyFactory(advisedSupport).getProxy(); } return null; }}
  • The main core of the DefaultAdvisorAutoProxyCreator class implementation is postProcessBeforeInstantiation method, From the beanFactory getBeansOfType obtain AspectJExpressionPointcutAdvisor began.
  • Obtained after advisors can traverse the corresponding AspectJExpressionPointcutAdvisor fill corresponding attribute information, including: the target object, intercept method, verifier, then returned proxy objects.
  • So now the Bean object that the caller gets is an object that has been injected by the aspect, and when the method is called, it is intercepted on demand to process the information that the user needs.

Five, the test

1. Prepare

public class UserService implements IUserService { public String queryUserInfo() { try { Thread.sleep(new Random(1).nextInt(100)); } catch (InterruptedException e) { e.printStackTrace(); } return "Xiao Fu Ge, 100001, Shenzhen "; } public String register(String userName) { try { Thread.sleep(new Random(1).nextInt(100)); } catch (InterruptedException e) { e.printStackTrace(); } return "user:" + userName + "success!" ; }}
  • There are two different methods in UserService, and you can add new classes to add tests. Later in our test procedure, we will add our interception handling to these two methods, and print method execution time.

2. Customize interception methods

public class UserServiceBeforeAdvice implements MethodBeforeAdvice { @Override public void before(Method method, Object[] args, Object target) throws Throwable {system.out.println (" Intercepting method: "+ method.getName()); }}
  • Instead of implementing the MethodInterceptor interface, as we did in the previous chapter, we implement MethodBeforeAdvice wrapping interception. In this method we can get some information about the method, and if we also develop its MethodAfterAdvice we can implement the two interfaces together.

3. Spring. XML to configure AOP

<beans> <bean id="userService" class="cn.bugstack.springframework.test.bean.UserService"/> <bean class="cn.bugstack.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/> <bean id="beforeAdvice" class="cn.bugstack.springframework.test.bean.UserServiceBeforeAdvice"/> <bean id="methodInterceptor" class="cn.bugstack.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor"> <property name="advice" ref="beforeAdvice"/> </bean> <bean id="pointcutAdvisor" class="cn.bugstack.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor"> <property name="expression" value="execution(* cn.bugstack.springframework.test.bean.IUserService.*(..) )"/> <property name="advice" ref="methodInterceptor"/> </bean> </beans>
  • This time using AOP can be configured in XML, just as in Spring. Because we have incorporated AOP functionality into the Bean lifecycle, your new interceptors will be handled automatically.

4. Unit testing

@Test public void test_aop() { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml"); IUserService userService = applicationContext.getBean("userService", IUserService.class); System. The out. Println (" test results: "+ userService. QueryUserInfo ()); }
  • In a unit test, you only need to retrieve and use the Bean object as normal, but if it is intercepted by a section, you will actually get the processing in the corresponding proxy object.

The test results

Test result: Xiao Fu Ge, 100001, Shenzhen Process Finished with exit code 0
  • As you can see from the test results, we have made the intercepting method work, and we don’t need to handle the sections, the intercepting method, etc.As you can see in the screenshot, IUserService is a proxy object

Six, summarized

  • The externalizing aspect of implementing AOP in this section is that it intercepts aspects that you used to intercept in unit tests and then leaves them to Spring’s XML configuration, so you don’t have to handle them manually. It is important to know how to integrate this functionality into Spring’s Bean lifecycle. The BeanPostProcessor is used in this chapter because it solves the problem of how to initialize a Bean object before it executes its initialization method. The extension point used to modify the new instantiated Bean object, so we can handle our own AOP proxy object logic.
  • The implementation of a function often includes the core part, the assembly part, and the link part. To fulfill these responsibilities, interfaces and classes need to be created, which are assembled by the inheritance and implementation of different relationships. Only when the division of responsibilities is clear, can the corresponding functional logic be flexibly expanded, otherwise it is difficult to control the development and construction of large-scale systems, which is the feeling that is not good to grasp.
  • Our current implementation of AOP is similar to the core logic in the Spring source code, but it is simpler and does not take into account the problems encountered in more complex scenarios, including whether there are constructors, whether it is an aspect in a proxy, and so on. In fact, we can see that as long as some features in Java, they need to be fully implemented in real Spring, otherwise you will encounter various problems when using these features.

Vii. Series recommendation

  • Full process source resolution for GetBeans in Spring
  • How do you plug beans into the Spring container?
  • SpringBoot middleware design and development
  • How close is mathematics to a programmer?
  • Six months recruitment screening 400+ resumes, tell you how to write easy to tease!