Foreword: feeling recently strenuous learned the motive power that it doesn’t matter to learn again a few days, hold to very difficult 😫. Back or a big section of a big section of the more bar, according to the day of hair is too mixed, sometimes a day can not learn a big concept, sometimes can learn several… Keep it up 🙃
Four, AOP
4.1 Basic Concepts
Concept: AOP (Aspect Oriented Programming), meaning: Aspect Oriented Programming, through pre-compilation and runtime dynamic proxy to achieve unified maintenance of program functions of a technology. AOP is a continuation of OOP, a hot topic in software development, and an important content in Spring framework. It is a derivative paradigm of functional programming.
Advantages: AOP can be used to isolate each part of the business logic, so that the degree of coupling between each part of the business logic is reduced, improve the reusability of the program, and improve the efficiency of development.
Main intention: The log records, performance statistics, security control, transaction processing, the exception handling code division from the business logic code, such as through the separation of these actions, we hope they can be independent to the guidance of business logic method, and then change the behavior does not affect the business logic code (i.e. don’t modify the source code way, Add new functionality to trunk functionality.
Example:
4.2 Underlying Principles
AOP uses dynamic proxies underneath, and there are two cases of dynamic proxies:
-
In the first interface case, the JDK dynamic proxy is used to create an interface to implement a class’s proxy object, enhancing the class’s methods
-
The second case, without an interface, uses CGLIB dynamic proxies to create subclass proxy objects and enhance the class’s methods
4.3 JDK Dynamic Proxy
Using the JDK dynamic Proxy, create Proxy objects using methods in the Proxy class
The Proxy class:
Create an object using the following method:
The method takes three parameters: the first parameter, the second parameter of the classloader, the class of the enhanced method, the interface that this class implements (supports multiple interfaces), or the interface that the proxy class needs to implement. The third parameter implements the interface InvocationHandler, creates the proxy object, and writes the enhanced part
Example:
â‘ Create interfaces and define methods
public interface UserService {
public void add(a);
public int update(int a,int b);
}
Copy the code
â‘¡ Create interface implementation class, implementation method
public class UserServiceImpl implements UserService{
@Override
public void add(a) {
System.out.println("The Add method of UserServiceImpl executes...");
}
​
@Override
public int update(int a, int b) {
System.out.println("UserServiceImpl update method executes...");
returna + b; }}Copy the code
â‘¢ Create a proxy object class to implement the InvocationHandler interface
// create a UserService interface proxy object class
public class UserServiceProxy implements InvocationHandler {
// Pass the object to be propped to the proxy class via the argument constructor
// The Object type used here can be changed to the specific Object type of the propped class. The Object type is used only for the purpose of propping up multiple objects
private Object obj;
public UserServiceProxy(Object obj){
this.obj = obj;
}
// Write the business logic that needs to be enhanced in the original function
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// Before executing the enhanced method
System.out.println("Before method execution...");
System.out.println("The method of execution is:" + method.getName());
System.out.println("The argument passed is:" + Arrays.toString(args));
// Execute the enhanced method
Object invoke = method.invoke(obj, args); // The underlying Method call, which can be explained in the Java basics section reflection, or in the Method class in the java.lang.Reflect package
// After executing the enhanced method
System.out.println("After method execution...");
System.out.println("This method returns the value:" + invoke);
System.out.println("The object that executes this method is:" + obj);
//System.out.println(proxy); Why here I want to output proxy will make the program always execute resulting in stack overflow exception, hope if there is a big guy carefully see can help me answer
return invoke;
}
// Invoke the invoke method of InvocationHandler.
//proxy - the proxy instance that calls the method
//method - the method invoked using the proxy object
//args - The array of parameters required by the method called by the proxy object
// Return result - the return value of the called method
The value returned from a method call on a proxy instance. If the declared return type of an interface method is primitive, the value returned by this method must be an instance of the corresponding base wrapper class.
// Otherwise, it must be a declarable return type. If the method returns a value of NULL and the interface method returns a primitive type, a NullPointerException will be thrown by the proxy instance's method call.
// As mentioned above, if this method returns a value that would otherwise not be compatible with the declared return type of the interface method, a ClassCastException will be thrown from the proxy instance's method call.
}
Copy the code
4 create an interface Proxy object using the Proxy class
public class JDKProxy {
public static void main(String[] args) {
// Create a proxy object for the interface implementation class
Class[] interfaces = {UserService.class}; // The type of interface that the created proxy object needs to implement
//1, create a proxy object for the UserService interface implementation class by creating the InvocationHandler anonymous implementation class object
//Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new InvocationHandler() {
// @Override
// public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// return null;
/ /}
/ /});
// create a proxy object for the UserService interface implementation class by creating an object for the InvocationHandler implementation class
UserServiceImpl userServiceImplProxied = new UserServiceImpl(); // Create an interface implementation object (proxied object)
System.out.println(Proxied interface implementation class object: + userServiceImplProxied);
// Create a proxy object for the UserService interface implementation class UserServiceImpl
UserService userServiceImplProxy = (UserService) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserServiceProxy(userServiceImplProxied));
userServiceImplProxy.add(); // The created proxy object calls the proxied object's methods
​
// Execution result:
/ / by proxy interface implementation class objects: com. Spring5. Bbe9ba UserServiceImpl @ 61
// Before the method is executed...
// The method is add
// The argument passed is null
// The add method of UserServiceImpl executes...
// After the method is executed...
// The value returned by this method is null
/ / execution object of this method is: com. Spring5. Bbe9ba UserServiceImpl @ 61}}Copy the code
4.4 Operation Terms
There are four common operational terms used in AOP, which are:
-
The join
- The methods that can be enhanced in a class are called join points
-
The breakthrough point
- The methods that are actually enhanced are called pointcuts
-
Notification (enhanced)
-
The part of the logical code that is actually enhanced is called the notification
-
Several types of notification:
- Pre notice
- The rear notice
- Surrounding the notification
- Abnormal notice
- Final notice
-
-
section
- Is an action, the process of applying advice to a pointcut is called an aspect
4.5 AOP operation
4.5.1 Preparations
1. The Spring framework generally implements AOP operations based on AspectJ
- AspectJ is not part of Spring, a stand-alone AOP framework that is typically used with the Spirng framework for AOP operations
2. Implement AOP operations based on AspectJ
- Implemented based on XML configuration files
- Annotation-based implementation (usually used)
3. Introduce AOP-related dependencies into your project
<! - maven import - >
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.3.15</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.3.16</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.8</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.8</version>
</dependency>
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>net.sourceforge.cglib</groupId>
<artifactId>com.springsource.net.sf.cglib</artifactId>
<version>2.2.0</version>
</dependency>
Copy the code
Pointcut expressions
- Pointcut expressions are used to know which methods in which classes are enhanced
- Grammatical structure:
Execution ([permission modifier] [return type] [class full path] [method name]([parameter list]))
- Example 1: Enhance the add method in the com.spring5.dao.bookdao class
execution(* com.spring5.dao.BookDao.add(..) )
- Example 2: Enhance all methods in the com.spring5.dao.bookdao class
execution(* com.spring5.dao.BookDao.* (..) )
- Example 3: Enhance all methods in all classes in the com.spring5.dao package
execution(* com.atguigu.dao.*.* (..) )
4.5.2 Annotation method based on AspectJ
1. Annotation method to implement AOP
1. Create a class and define methods in it
public class User {
public void add(a){
System.out.println("user add..."); }}Copy the code
2. Create an enhancement class (write the enhancement logic). Within the enhancement class, create methods that represent different notification types
/ / the proxy class
public class UserProxy {
public void before(a){
System.out.println("Pre-notification..."); }}Copy the code
1. Enable annotation scanning in the Spring configuration file (you can also enable annotation scanning in annotation mode)
// Annotation mode
@Configuration
@ComponentScan(basePackages = {"com.spring5.aopannotation"})
public class SpringConfig {}Copy the code
<! -- Configuration file mode -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<! -- Enable annotation scan -->
<context:component-scan base-package="com.spring5.aopannotation"></context:component-scan>
</beans>
Copy the code
â‘¡ Use annotations to create User and UserProxy objects
@Component
public class User {
public void add(a){
System.out.println("user add..."); }}@Component
public class UserProxy {
public void before(a){
System.out.println("Pre-notification..."); }}Copy the code
â‘¢ Add the @aspect annotation to the enhanced (proxy) class
@Component
@Aspect
public class UserProxy {
public void before(a){
System.out.println("Pre-notification..."); }}Copy the code
4 Enable the generation of proxy objects in the Spring configuration file
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<! -- Enable annotation scan -->
<context:component-scan base-package="com.spring5.aopannotation"/>
<! -- Enable Aspect generation proxy object -->
<aop:aspectj-autoproxy/>
</beans>
Copy the code
4. Configure different types of notification by adding notification type annotations above the notification method in the enhanced class, using the pointcut expression configuration
@Component
@Aspect
public class UserProxy {
// Pre-notification
The @before annotation is used as a pre-notification
@Before("execution(* com.spring5.aopannotation.User.add())")
public void before(a){
System.out.println("before...");
}
// Final notification -- executes regardless of whether there are exceptions during execution
@After("execution(* com.spring5.aopannotation.User.add())")
public void after(a){
System.out.println("after...");
}
// Post-notification (return notification) -- no execution if an exception occurs during execution
@AfterReturning("execution(* com.spring5.aopannotation.User.add())")
public void afterReturning(a){
System.out.println("afterReturning...");
}
// Exception notification
@AfterThrowing("execution(* com.spring5.aopannotation.User.add())")
public void afterThrowing(a){
System.out.println("afterThrowing...");
}
// Wrap around the notification
@Around("execution(* com.spring5.aopannotation.User.add())")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("Around before...");
// Execute the enhanced method
proceedingJoinPoint.proceed();
System.out.println("After circling..."); }}Copy the code
5, test,
public class TestSpring5 {
@Test
public void test(a){
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
User user = context.getBean("user", User.class);
user.add();
// Surround before...
//before...
//user add...
//afterReturning...
//after...
// After circling...
// The output of the last three may be different due to the Spring version, it seems that someone said that the bottom layer has changed since 5.3.7}}// In addition, in the Around notification method, try-catch is used to handle exceptions and the output is still executed "after wrapping" when the code executes an exception, but throws exception handler "after wrapping" when the code executes an exception
Copy the code
2. Extract common pointcuts
@Pointcut("execution(* com.spring5.aopannotation.User.add())")
public void pointDemo(a){}// Pre-notification
The @before annotation is used as a pre-notification
@Before("pointDemo()")
public void before(a){
System.out.println("before...");
}
// Final notification
@After("pointDemo()")
public void after(a){
System.out.println("after...");
}
Copy the code
3. Priority of multiple enhancement classes
When more than one enhancement class enhances the same method, you can set the priority of the enhancement class by adding the @ORDER annotation to the enhancement class. The smaller the numeric value, the higher the priority
/ / PersonProxy enhancement class
@Component
@Aspect
@Order(1)
public class PersonProxy {
@Pointcut("execution(* com.spring5.aopannotation.User.add())")
public void pointDemo(a){}// Pre-notification
@Before("pointDemo()")
public void before(a){
System.out.println("personProxy before...");
}
// Final notification
@After("pointDemo()")
public void after(a){
System.out.println("personProxy after..."); }}/ / UserProxy enhancement class
@Component
@Aspect
@Order(3)
public class UserProxy {
@Pointcut("execution(* com.spring5.aopannotation.User.add())")
public void pointDemo(a){}// Pre-notification
The @before annotation is used as a pre-notification
@Before("pointDemo()")
public void before(a){
System.out.println("userProxy before...");
}
// Final notification
@After("pointDemo()")
public void after(a){
System.out.println("userProxy after..."); }}/ / test
@Test
public void test(a){
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
User user = context.getBean("user", User.class);
user.add();
//personProxy before...
//userProxy before...
//user add...
//userProxy after...
//personProxy after...
}
Copy the code
4. Fully annotated development
// Create a configuration class without creating an XML configuration file
@Configuration
@ComponentScan(basePackages = {"com.spring5.aopannotation"})
@EnableAspectJAutoProxy(proxyTargetClass = true) // Enable the Aspect generation proxy object
public class ConfigAop {}Copy the code
4.5.3 XML configuration file based on AspectJ
1. Create two classes, the enhanced class and the enhanced class, and create methods
public class Book {
public void buy(a){
System.out.println("book buy..."); }}public class BookProxy {
public void before(a) {
System.out.println("bookProxy before..."); }}Copy the code
2. Create two class objects in the Spring configuration file
<! Create object -->
<bean id="book" class="com.spring5.aopxml.Book"/>
<bean id="bookProxy" class="com.spring5.aopxml.BookProxy"/>
Copy the code
Configure the pointcut in the Spring configuration file
<! Need to introduce aop namespace -->
<! Configure AOP enhancement -->
<aop:config>
<! Configure pointcuts -->
<aop:pointcut id="proxied" expression="execution(* com.spring5.aopxml.Book.buy())"/>
<! -- Configure the section (section)-->
<aop:aspect ref="bookProxy">
<! -- Enhanced effect on specific methods (notifications)-->
<aop:before method="before" pointcut-ref="proxied"/>
</aop:aspect>
</aop:config>
Copy the code
test
@Test
public void test1(a){
ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");
Book book = context.getBean("book", Book.class);
book.buy();
//bookProxy before...
//book buy...
}
Copy the code
Hope there are big guy can see me in 4.3 in the example of the third step of the doubt, and then give me the answer, very grateful 😃