The article has been hosted on GitHub, you can go to GitHub to view and read, welcome bosses to Star! Search wechat public number [code out Offer] to receive a variety of learning materials!
SpringAOP
What is AOP
Aspect Oriented Programming (AOP), or section-oriented Programming, uses a technique called “crosscutting” to cut open the interior of wrapped objects and encapsulate the common behavior that affects multiple classes into a reusable module named “Aspect”, or Aspect. The so-called “facets”, simply speaking, are those unrelated to the business, but are encapsulated by the logic or responsibility of business modules, which is convenient to reduce the repetitive code of the system, reduce the degree of coupling between modules, and is conducive to the future operability and maintainability.
Application scenarios: Such as logging, auditing, declarative transactions, security, and caching.
Ii. Scenario analysis
To better understand AOP, infiltrate the idea of section-oriented programming. Let me give you an example that is very common in development. Print log
First, we need to understand what logging is.
Logging: Logging is a way to keep track of what is happening while some software is running, and software developers can call logging related methods into their code to indicate that something is happening. An event can be described by a message that contains optional variable data. In addition, an event also has the concept of importance, which can also be called a severity level. Developers can analyze the desired information by differentiating severity levels.
Knowing what a log is, you need to know how and where to print a log. To print logs, import dependencies and use log tools to print log severity levels and log information. Where to print the log is, of course, a key place in our project code.
Here is an example of A code before and after the use of three methods, A, B, C, but before calling each method, require A line of log “A method was called!” After each method is called, it is also required to print the log “a method has been called!” .
Ordinary people can be in the beginning and the end of each method is printed, add a log to do so much more if the method, will have a lot of repetitive code, appear very trouble, someone will think of, why don’t you encapsulate print log this feature, and then make it can in the specified place (such as the execution method before, or after the execution method) automatically to call? If you can, the business function code is not mixed with this other code, so AOP does just that.
Its working principle is JDK dynamic proxy and CGLIB dynamic proxy, here will not expand the knowledge of dynamic proxy! Or see AOP first!
AOP terminology
What AOP does: Spring’s AOP programming is all about adding helper functionality to the methods of the original class through dynamic proxy classes.
AOP terminology | describe |
---|---|
The join (Joinpoint) | Join points are methods that exist objectively in a program class and can be intercepted by Spring to cut into content |
Point (Pointcut) | Cut into the join point by Spring |
Advice | Additional capabilities can be added to pointcuts: pre-notification, post-notification, exception notification, surround notification, and so on. |
Target Object | The target object of the proxy |
Introduction (the Introduction) | A special enhancement that dynamically adds Field and Method to a class at run time |
Weave (has) | The process of creating a new proxy class by applying advice to a concrete class |
The agent (Proxy) | The resulting class that is woven into the advice by AOP |
Section (Aspect) | Consists of pointcuts and notifications that weave crosscutting logic into the join points specified by the section |
Four, AOP terminology analysis
3.1 points
Simply put, a place that allows you to use notifications, enhancements. Just like printing logs before and after methods, we can do things before and after a piece of code, we can do things after a piece of code, we can do things after a piece of code throws exceptions. So, lines of code (methods, etc.) that can be manipulated here are join points.
3.2 point
Looking at code such as method by method as join points, where do we print logs (enhancement operations), and where do we pick out where we need to print logs (around join points), known as pointcuts.
3.3 Enhancement and notification
In terms of enhancements, AS I mentioned above, actions done through pointcuts are called enhancements, such as when we print logs, and logging is an enhancement operation.
3.4 Target Objects
The target object is simply the object to be enhanced.
3.5 introduction
Allows us to add new method attributes to existing classes. This does not apply the aspect (that is, the new method property defined by the enhancement) to the target object
3.6 woven into
The process of creating a new proxy class by applying enhancements to specific target objects
3.7 the agent
A proxy is just like the mediation we used to buy a house, that is, a proxy object (mediation object) that is woven into AOP to enhance our target object
Section 3.8
A section is a combination of advice (enhancement) and pointcuts. Advice says what to do and when, and pointcuts say where to do, which is a complete aspect definition.
Five, SpringAOP development steps
5.1 The POM.xml file introduces dependencies
Introducing Spring core dependencies (Spring-Context) and SpringAOP dependencies (Spring-Aspects)
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> < version > 5.1.6. RELEASE < / version > < / dependency > < the dependency > < groupId > org. Springframework < / groupId > < artifactId > spring - aspects < / artifactId > < version > 5.1.6. RELEASE < / version > < / dependency >Copy the code
5.2 Create the spring-context. XML file and add a schema
We need to add the AOP and context’s Schema to the header of the core configuration file
<? The XML version = "1.0" encoding = "utf-8"? > <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd "> </beans>Copy the code
5.3 Defining primitive classes
The simulation creates a primitive class
public interface UserService {
public void save(a);
}
public class UserServiceImpl implements UserService {
public void save(a) {
System.out.println("save method executed..."); }}Copy the code
5.4 Define the pass class
Define notification classes (add additional enhancements)
public class MyAdvice implements MethodBeforeAdvice { // Implement the pre-notification interface
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("before advice executed..."); }}Copy the code
5.5 define the bean
Configuring bean objects
<! -- Primitive object --> <bean id="us" class="com.mylifes1110.service.impl.UserServiceImpl"/ > <! -- Auxiliary (enhanced) object --> <bean id="myAdvice" class="com.mylifes1110.advice.MyAdvice" />
Copy the code
5.6 Defining pointcuts to form facets
Define pointcuts and form aspects
<aop:config> <! Aop :pointcut id="myPointCut" expression="execution(* save())" /> <! <aop:advisor advice-ref="myAdvice" pointcut-ref="myPointCut" /> </aop:config>Copy the code
5.7 Enhancement Results
Use pre-notification to result in enhanced print statements before Advice executed… Save method executed… is printed before the save() method. .
Six, notifications,
Define notification classes for notification (enhancement) effect. Implement different interfaces and override methods to achieve different notification effects
Notice the name | interface | describe |
---|---|---|
Pre notice | MethodBeforeAdvice interface | Enhance in front of the target object |
The rear notice | AfterAdvice interface | Note: the method in this interface is empty, and the third method is used by default |
The rear notice | AfterReturningAdvice interface | Make enhancements after the target object |
Abnormal notice | ThrowsAdvice | Enhance the target object after an exception occurs |
Surrounding the notification | MethodInterceptor | Enhance before and after the target object |
Seven, wildmatch entry point
Wildcard pointcuts based on expressions
Wildcard expression order: Return value type full class name. Method name (parameter)
Note: You can use.. To implement the wildcard parameter list, use * to wildcard the method name or return value type
<! --public int com.mylifes1110.service.UserServiceImpl.queryUser(int,String,com.entity.User) --> <! < AOP :pointcut id="myPointCut" expression="execution(* *(com.mylifes1110.bean.User))"/ > <! --> < AOP :pointcut id="myPointCut" expression="execution(* save())"/ > <! --> < AOP :pointcut id="myPointCut" expression="execution(* save(..) )"/ > <! Aop :pointcut id="myPointCut" expression="execution(com.mylifes1110.bean.User *(..) )"/ > <! < AOP :pointcut id="myPointCut" expression="execution(* com.mylifes1110.bean.UserServiceImpl.*(..) )"/ > <! < AOP :pointcut id="myPointCut" expression="execution(* com.mylifes1110.bean.*.*(..) )"/ > <! < AOP :pointcut id="myPointCut" expression="execution(* com.mylifes1110.. *. * (..) )" />
Copy the code
8. Agent mode
8.1 Agent Mode
Separating core functions from auxiliary functions (transaction, log, performance monitoring code) makes core business functions purer and auxiliary business functions reusable.
Functional separation |
---|
8.2 Application Scenario Simulation of proxy Mode
Through the object of the proxy class, adding auxiliary functions for the object of the original class (object of the target class), it is easier to change the proxy implementation class and facilitate maintenance.
Scenario simulation: We need to go through the following process in renting a house:
- Release rental information
- Show tenants houses
- Sign the contract
- Collect the rent
But what if you’re a landlord and have other chores in your life? Then can you give the unimportant and not the core link to the intermediary (agent) to do? For example: release rental information and show tenants. It is ok to leave these two things to the intermediary. We can deal with our own affairs by ourselves, and we can go through important procedures, such as signing contracts and collecting rent, by contacting tenants well.
8.3 Creating a Service Interface and Implementation Class
Create Service interfaces and implementation classes to simulate the application scenario of dynamic proxies
package com.mylifes1110.service;
public interface LandlordService {
void rent(a);
}
package com.mylifes1110.service.impl;
import com.mylifes1110.service.LandlordService;
public class LandlordServiceImpl implements LandlordService {
@Override
public void rent(a) {
System.out.println("Sign a contract");
System.out.println("Payment"); }}Copy the code
8.4 Static Proxy
The following is the static proxy design pattern to solve the proxy problem
- Static proxy process, create a proxy class and implement the same interface, create the implementation class object, add auxiliary functions in the proxy class and call the core method of the implementation class object, make the auxiliary functions and core method trigger together, complete the proxy
- Static proxy problems
- As the number of helper functions increases, so does the number of proxy classes, resulting in an excessive number of proxy classes, which is not conducive to project management.
- The auxiliary function code of multiple proxy classes is redundant, and when modified, the maintainability is poor.
Static agent |
---|
Create a static proxy class
package com.mylifes1110.advice1;
import com.mylifes1110.service.LandlordService;
import com.mylifes1110.service.impl.LandlordServiceImpl;
/ * * *@ClassName Proxy
* @DescriptionStatic proxy class *@Author Ziph
* @Date 2020/7/19
* @Since 1.8
* @Version1.0 * /
public class Proxy implements LandlordService {
private LandlordService landlordService = new LandlordServiceImpl();
@Override
public void rent(a) {
// Proxy events
System.out.println("Release the news.");
System.out.println("Look at the house");
// Core eventlandlordService.rent(); }}Copy the code
Static proxy implementation
package com.mylifes1110.advice1;
import org.junit.Test;
public class ProxyTest {
/ * * *@MethodName proxyTest
* @Param []
* @DescriptionStatic proxy implementation *@Author Ziph
* @Date2020/7/10 * /
@Test
public void proxyTest(a) {
new Proxy().rent();
}
/** * Results: ** Release information * see the house * sign the contract * receive payment */
}
Copy the code
8.5 JDK and CGLIB selection
Spring base includes JDK proxy and Cglib proxy.
The basic rule is: the target business class uses a JDK proxy if it has an interface, and a CGLib proxy if it does not. If true: <aop:config proxy-target-class=”true”>, use the CGLIB proxy
class DefaultAopProxyFactory{
// The JDK proxy and CGLib proxy selection rules are clearly defined in this method
// The basic rule is: the target business class uses JDK proxies if it has interfaces, and CGLib proxies if it does not
public AopProxy createAopProxy(a){...}
}
Copy the code
8.6 JDK Dynamic Proxy
JDK dynamic proxies are implemented at the bottom of the JDK based on interfaces, which means we must implement JDK dynamic proxies interfaces and override methods to do this
package com.mylifes1110.advice2;
import com.mylifes1110.service.LandlordService;
import com.mylifes1110.service.impl.LandlordServiceImpl;
import org.junit.Test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyTest {
/ * * *@MethodName proxyTest
* @Param []
* @DescriptionJDK dynamic proxy implementation *@Author Ziph
* @Date2020/7/10 * /
@Test
public void proxyTest(a) {
// The target that needs to use the proxy
LandlordService landlordService = new LandlordServiceImpl();
// Anonymous inner class
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// Proxy events
System.out.println("Release the news.");
System.out.println("Look at the house");
returnmethod.invoke(landlordService, args); }};// Dynamically build the proxy class
LandlordService proxy = (LandlordService) Proxy.newProxyInstance(ProxyTest.class.getClassLoader(),
landlordService.getClass().getInterfaces(),
handler);
proxy.rent();
/** * Results: ** Release information * see the house * sign the contract * receive payment */}}Copy the code
8.7 CGLIB Dynamic Proxy
CGLIB dynamic proxies are implemented under Spring based on inherited superclasses, which means we must do this by inheriting the specified superclass and overriding its methods
package com.mylifes1110.advice3;
import com.mylifes1110.service.LandlordService;
import com.mylifes1110.service.impl.LandlordServiceImpl;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.InvocationHandler;
import java.lang.reflect.Method;
/ * * *@ClassName ProxyTest
* @DescriptionCGLIB dynamic proxy implementation *@Author Ziph
* @Date 2020/7/19
* @Since 1.8
* @Version1.0 * /
public class ProxyTest {
public static void main(String[] args) {
final LandlordService landlordService = new LandlordServiceImpl();
// Create a bytecode enhancement object
Enhancer enhancer = new Enhancer();
// Set the parent class (equivalent to implementing the primitive class interface)
enhancer.setSuperclass(landlordService.getClass());
// Set the callback function (extra function code)
enhancer.setCallback(new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
// Proxy events
System.out.println("Release the news.");
System.out.println("Look at the house");
Object ret = method.invoke(landlordService, args);
returnret; }});// Create a dynamic proxy class
LandlordService proxy = (LandlordService) enhancer.create();
proxy.rent();
/** * Results: ** Release information * see the house * sign the contract * receive payment */}}Copy the code
9. Rear processor
9.1 Post-processor understanding
- Many post-processors are defined in Spring;
- Before each bean is created, there will bea post-processing process, namely reprocessing, to make relevant changes and adjustments to the bean;
- In Spring-AOP, there is a specialized post-processor that is responsible for reprocessing a proxy component from the original business component (Service).
Common post processor |
---|
9.2 Defining a post-processor
/** * After the bean is created, it reprocesses the bean */
public class MyBeanPostProcessor implements BeanPostProcessor{
/** * is executed before the bean's init method@paramBean The original bean object *@param beanName
* @return
* @throws BeansException
*/
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Post-processor executes before init" + bean.getClass());
return bean;
}
/** * executes after the bean's init method@paramThe bean bean postProcessBeforeInitialization back *@param beanName
* @return
* @throws BeansException
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Post-processor executes after init ~~~" + bean.getClass());
return bean;// The return here is the final return value of getBean()}}Copy the code
9.3 Configuring cpus
<! - processor after configuration, will all the bean declaration in the cycle to the factory to intervene - > < bean class = "com. Mylifes1110. Beanpostprocessor. MyBeanPostProcessor" > < / bean >Copy the code
9.4 Bean life cycle
Create Bean object -> Constructor -> Setter method to inject properties, satisfy dependencies -> post-processor pre-procedure -> Init initialization -> post-processor post-procedure -> Build complete -> Destroy
9.5 Dynamic Proxy source Code (Understanding)
/ / AbstractAutoProxyCreator AspectJAwareAdvisorAutoProxyCreator parent / / the handler class after wrapIfNecessary method in the dynamic proxy generation process AbstractAutoProxyCreator#postProcessAfterInitialization(Object bean, String beanName){ if (! This. EarlyProxyReferences. The contains (cacheKey)) {/ / dynamic custom agent return wrapIfNecessary (bean, beanName cacheKey); }}Copy the code