From the previous chapter [Mastering the Spring Framework Part 2]

The life cycle of the bean

Reference: javainsimpleway.com/spring-bean…

This is a very basic but very frequent interview question. If an interviewer asks you what is the life cycle of spring beans? So what’s the answer? You can analyze the question before you answer. First of all, what is the interviewer’s purpose in asking this question? If I were the interviewer, I would want to get a sense of what the candidate knows about the Spring framework and how it manages beans. What we can participate in throughout the bean pair lifecycle. What are the common scenarios? Is there any difference in the life cycle of different types of beans? If the candidate can clearly state these questions, then I think he passed the interview question. The purpose of learning the life cycle of a bean is to extend it freely in the real world. To meet business needs. Let’s analyze the bean life cycle from these aspects.

First look at this picture below, source: javainsimpleway.com/spring-bean…

  1. First instantiatebean
  2. populateBean
  3. All are called first before calling the initialization methodbeantheHave a perceptionMethods includingBeanNameAware.BeanClassLoaderAware.BeanFactoryAware.
  4. Then performBeanPostProcessorthepostProcessBeforeInitialization
  5. Perform the initialization method if the bean is implementedInitializingBeanHe will be calledafterPropertiesSetMethods. Like I mentioned earlierRepositoryFactoryBeanSupportthroughafterPropertiesSetforrepositoryCreation.
  6. Reflection calls custominit-methodMethods.
  7. Then performBeanPostProcessorthepostProcessAfterInitialization

Which when executed to ApplicationContextAwareProcessor postProcessBeforeInitialization, call the bean method of application level of awareness. Such as ApplicationContext ware, EnvironmentAware, etc.

We are familiar with the BeanPostProcessor AutowiredAnnotationBeanPostProcessor, used for automatic assembly.

RequiredAnnotationBeanPostProcessor, it can make sure that the statement “essential attribute” bean actually configured value, or you will surely like the following error

@ PostConstruct and @ PreDestroy CommonAnnotationBeanPostProcessor processing, Perform @ PostConstruct logic is in its superclass InitDestroyAnnotationBeanPostProcessor postProcessBeforeInitialization. Execution of the @ PreDestroy logic was conducted in InitDestroyAnnotationBeanPostProcessor postProcessBeforeDestruction.

So when @postconstruct executes, the bean’s properties are already loaded. It is executed only once and can perform some initialization that requires dependencies.

@predestroy takes advantage of the shutdown hook in the JDK to gracefully shutdown applications. Note that the shutdown hook should not perform time-consuming operations, which would cause the program to fail to exit properly. When o&M scripts are written, a timeout period is set. If the timeout period is exceeded, run the kill -9 command to forcibly exit the script.

Spring-managed beans are singletons by default. All scopes for a bean have the following

Source: Spring official documentation

The Request Session Application exists only in the context of a Web application. Websocket Exists in the WebSocket environment. This article will not go into detail, but singleton readers will already be familiar with it, so let’s focus on the prototype type.

@Component
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class A {}Copy the code

Define a simple class and declare scope as Prototype. After the spring invoked applicationContext. GetBean (” a “), the code process roughly as follows.

  1. callAbstractBeanFactorythedoGetBeanmethods
  2. Decide to throw an exception directly if the prototype bean is being created.
  3. Get the correspondingBeanDefinition, judge if it isPrototypetype
  4. callbeforePrototypeCreationTag being created
  5. createBeancreatebean, and creating singletonsbeanIt’s the same method.
  6. callafterPrototypeCreationRemove tag

So prototype-type beans do not support loop dependencies. Also, since it is the same method as the bean that created the Singleton, all the bean’s aware methods are similar. One important difference is that the @Predestroy of the prototype bean is not executed. The reason is simple: the destroy method is implemented by shutdownHook calling the beanFactory destroySingletons method. Spring does not define destruction actions for ProtoTypeBeans.

More detailed explanation can refer to: bluebreeze0812. Making. IO/learn / 2019 /…

Spring dynamic proxy with AOP

The proxy pattern

The proxy pattern is one of the 23 commonly used Java design patterns in GoF and falls under the structural pattern. One common application scenario is RPC frameworks such as service calls in Dubbo. A locally invoked service is actually a proxy object for a remote object. A method that calls a proxy object actually calls a method of a remote object. JAVA RMI, of course, won’t describe remote proxies too much here. Today we are going to talk about Spring’s dynamic proxy. As we all know, the Spring proxy is really a wrapper around the JDK proxy and the CGLIB proxy. So let’s take a look at the JDK and the Cglib proxy. This is also an essential ingredient for cooking spring AOP.

JDK dynamic proxy

public class JdkProxyDemo {
    public interface Calculator {
        int add(int a, int b);
        int subtract(int a, int b);
    }
    public static class CalculatorImpl implements Calculator {
        @Override
        public int add(int a, int b) {
            return a + b;
        }
        @Override
        public int subtract(int a, int b) {
            returna - b; }}public static class ProxyFactory implements InvocationHandler {
        private final Calculator real;
        public ProxyFactory(Calculator real) {
            this.real = real;
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("before");
            Object result = method.invoke(real, args);
            System.out.println("after");
            returnresult; }}public static void main(String[] args) {
        Calculator real = new CalculatorImpl();
        ProxyFactory proxyFactory = new ProxyFactory(real);
        Calculator proxy = (Calculator) Proxy.newProxyInstance(real.getClass().getClassLoader(), new Class[]{Calculator.class}, proxyFactory);
        System.out.println(proxy.add(1.2));
        System.out.println(proxy.subtract(2.1)); }}Copy the code

From this simple example, you can conclude that the JDK dynamic proxy has the following features.

  1. Creating a proxy object requires three elements: a classloader and a list of interfaces that the proxy object needs to implement.InvocationHandlerInstance.

  1. The class of the proxy object iscom.sun.proxy.$Proxy0To achieve theCalculatorinterface
  2. Proxy object holdingInvocationHandlerInstance reference, andInvocationHandlerHolds a reference to the proxied object.
  3. InvocationHandlerThe Invoke method of the invoke method proxies all methods of the interface. You can add logic before and after being executed by the proxy object, without even calling the proxy object’s methods.
  4. A list of interfaces that the proxy object needs to implement is required. This is the biggest feature of JDK dynamic proxies. Both proxied and proxied objects implement a common interface. Otherwise it cannot be deputized.

Cglib dynamic proxy

Bytecode generation library, which encapsulates ASM, is a bytecode manipulation framework, similar to javaassit, which basically parses a.class file and dynamically modifs it.

public class CglibProxyDemo {
    public static class Calculator {
        public int add(int a, int b) {
            returna + b; }}public static class CalculatorInterceptor implements MethodInterceptor {
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            System.out.println("before add");
            Object o1 = methodProxy.invokeSuper(o, objects);
            System.out.println("after add");
            returno1; }}public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Calculator.class);
        enhancer.setCallback(new CalculatorInterceptor());
        Calculator calculator = (Calculator) enhancer.create();
        System.out.println(calculator.add(1.2)); }}Copy the code

From the simple example above, we can conclude that cglib dynamic proxy has the following characteristics:

  1. The class of the generated proxy object iscom.family.spring.core.CglibProxyDemo$Calculator$$EnhancerByCGLIB$$b4da3734
  2. It is aCalculatorA subclass of class. Following inheritance rules, subclasses cannot override private methods of their parent class. That is, private methods cannot be proxied.
  3. MethodInterceptorDefines a method interceptor. The interceptor intercepts all proachable methods of the proxy class. You can also decide whether to call the real method of the parent class.
  4. There are two important differences between cglib proxies and JDK proxies: first, there is no need for a common interface, and second, there is no need to prepare a proxied object.

If the reader is interested in what the class structure of the agent actually looks like. You can also use Java proxy technology to read the corresponding class file in the JVM for analysis.

Spring Dynamic Proxy

Why YOU need AOP

Software development is a process of evolution, from the original POP(procedural programming) to OOP(object-oriented programming) to AOP(aspect programming), and probably a bunch of OP’s in the future, each programming idea is a product of software development evolution. They were created to solve a specific problem. So what is the background of AOP. I think as software systems get more complex, there is more and more stuff that is not related to the core business logic. For example: logging, permission validation, transaction control, error message detection. And that logic is scattered everywhere in the program. This not only increases the complexity and effort of writing code, but also greatly increases the maintenance cost of the code. Authentication, for example, is a pain if each interface has handwritten code to determine whether the current user has access to that interface. So clever programmers want to put the code in the same place, and then adopt the method of dynamic implant is added to the business before, during and after the code to perform this unified code, code and business logic inside can hardly see added, programmers can concentrate on CRUD, this is the name on the design ideas have a tall AOP, Aspect Oriented Programming wikipedia calls this Programming paradigm. In order to make this design concept more professional, also specially introduced a bunch of technical terms. Here’s a brief explanation of what each term means.

The term meaning
Notify the Advice Similar to the permission validation mentioned earlier, SpringaopThere are five types of notification: pre notification, post notification, exception notification, final notification and surround notification
The join JoinPoint This is where notifications are allowed, such as method join points (before and after method execution), exception join points (when an exception is thrown), and so on
Point of tangency Pointcut The join points woven into the advice are called cut points.
Cut the Aspect A section is a combination of notifications and pointcuts, which together define the three elements of a section:What to do.When to do.And where to do.
Weave has The process of creating a new proxy object by applying a facet to the target object

With this conceptual understanding, our approach to Spring AOP remains theoretical. So what does his implementation look like? Here’s a simple example to find out. Core code:

@Aspect
@Component
public class MonitorAspect {
    @Pointcut("execution(* com.family.spring.core.. *. * (..) )"
    public void pointCut(a) {}@Around("pointCut()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        Object result = pjp.proceed();
        stopWatch.stop();
        System.out.println("Performing" + pjp.getSignature().getName() + "All spent." + stopWatch.getTotalTimeMillis() + "毫秒");
        returnresult; }}@SpringBootApplication
@EnableAspectJAutoProxy
public class SpringAopDemoApplication implements ApplicationRunner {
    @Autowired
    private ApplicationContext applicationContext;
    public static void main(String[] args) {
        SpringApplication.run(SpringAopDemoApplication.class, args);
    }
    @Override
    public void run(ApplicationArguments args) throws Exception {
        UserService userService = (UserService) applicationContext.getBean("userService"); userService.login(); userService.register(); }}//userService is simple. It defines two methods: login Register
Copy the code

The program output looks like this:

It took 1000 milliseconds to execute login 2000 milliseconds to execute register 3009 milliseconds to execute run

The userService obtained by getBean must be the object after the proxy. So when did it get proxied. Debug finds that all beanPostProcessors are called for processing one by one during bean initialization. One of the special Processor is: AnnotationAwareAspectJAutoProxyCreator, and the introduction of the Processor is @ EnableAspectJAutoProxy. Open the annotation of the @ EnableAspectJAutoProxy source found that its core is to import a AspectJAutoProxyRegistrar (AspectJ automatic proxy registrar) class. And the role of this class is to registry AnnotationAwareAspectJAutoProxyCreator the BeanPostProcessor. Is it the same as @EnableJpaRepositories? Clues found, the following is the anatomy its postProcessAfterInitialization method.

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
		if(bean ! =null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			if (this.earlyProxyReferences.remove(cacheKey) ! = bean) {returnwrapIfNecessary(bean, beanName, cacheKey); }}return bean;
}
//wrapIfNecessary is used to generate proxy objects.
Copy the code

Continue to follow up and finally find the object proxy culprit. That’s our ProxyFactory

ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);

if(! proxyFactory.isProxyTargetClass()) {if (shouldProxyTargetClass(beanClass, beanName)) {
    proxyFactory.setProxyTargetClass(true);
  }
  else {
    evaluateProxyInterfaces(beanClass, proxyFactory);
  }
}

Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);

proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
  proxyFactory.setPreFiltered(true);
}

return proxyFactory.getProxy(getProxyClassLoader());
Copy the code

This is a wrapper class for Spring’s JDK and Cglib dynamic proxies. Its createAopProxy method in getProxy looks like this.

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
		if(! IN_NATIVE_IMAGE && (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))) { Class<? > targetClass = config.getTargetClass();if (targetClass == null) {
				throw new AopConfigException("TargetSource cannot determine target class: " +
						"Either an interface or a target is required for proxy creation.");
			}
			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
				return new JdkDynamicAopProxy(config);
			}
			return new ObjenesisCglibAopProxy(config);
		}
		else {
			return newJdkDynamicAopProxy(config); }}Copy the code

> > optimize, > > proxyTargetClass, > > cglib dynamic proxy, > > JDK dynamic proxy In addition, even if there is an opportunity to use Cglib, if the target class is an interface, the JDK dynamic proxy will be used. Let’s take a look at the aspect abstraction in SPing AOP

With the ProxyFactory proxy object, you must add notifications. If there is no notification, it is as if the proxy receives money but does nothing. An easy way to add it is to pass in a MethodInterceptor that intercepts it.

proxyFactory.addAdvice((MethodInterceptor) invocation -> {
      System.out.println("before");
      Object result = invocation.proceed();
      System.out.println("after");
      return result;
});
Copy the code

But the more advanced way is to add Advisor, which can be translated as Advisor, and have the Advisor tell me what the notification is? Spring built a powerful adviser, called InstantiationModelAwarePointcutAdvisorImpl, its getAdvice method, to dynamically return different types of notification. See: ReflectiveAspectJAdvisorFactory getAdvice method. BeanPostProcessor added this advisor to implement surround notification.

To be continued, please pay attention to chapter 4 of mastering the Spring Framework for more content