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…
- First instantiate
bean
populateBean
- All are called first before calling the initialization method
bean
theHave a perception
Methods includingBeanNameAware
.BeanClassLoaderAware
.BeanFactoryAware
. - Then perform
BeanPostProcessor
thepostProcessBeforeInitialization
- Perform the initialization method if the bean is implemented
InitializingBean
He will be calledafterPropertiesSet
Methods. Like I mentioned earlierRepositoryFactoryBeanSupport
throughafterPropertiesSet
forrepository
Creation. - Reflection calls custom
init-method
Methods. - Then perform
BeanPostProcessor
thepostProcessAfterInitialization
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.
- call
AbstractBeanFactory
thedoGetBean
methods - Decide to throw an exception directly if the prototype bean is being created.
- Get the corresponding
BeanDefinition
, judge if it isPrototype
type - call
beforePrototypeCreation
Tag being created createBean
createbean
, and creating singletonsbean
It’s the same method.- call
afterPrototypeCreation
Remove 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.
- Creating a proxy object requires three elements: a classloader and a list of interfaces that the proxy object needs to implement.
InvocationHandler
Instance.
- The class of the proxy object is
com.sun.proxy.$Proxy0
To achieve theCalculator
interface - Proxy object holding
InvocationHandler
Instance reference, andInvocationHandler
Holds a reference to the proxied object. InvocationHandler
The 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.- 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:
- The class of the generated proxy object is
com.family.spring.core.CglibProxyDemo$Calculator$$EnhancerByCGLIB$$b4da3734
- It is a
Calculator
A subclass of class. Following inheritance rules, subclasses cannot override private methods of their parent class. That is, private methods cannot be proxied. MethodInterceptor
Defines 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.- 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, Springaop There 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