AOP introduction
AOP (aspect oriented programming) is called: aspect oriented programming, which is a kind of programming idea. AOP is the continuation of OOP (Object Oriented Programming)
AOP adopts horizontal extraction mechanism to replace the traditional vertical inheritance system of repetitive code writing (such as performance monitoring, transaction management, security check, cache, logging, etc.)
AOP core idea
Based on the idea of agent, the agent object is created for the original target object. Without modifying the original object code, the original business method is enhanced by calling the enhanced code through the agent object
Aspect: need to proxy some methods and enhance code
AOP application scenarios
Scenario 1: log
Scenario 2: monitoring method run time (monitoring performance)
Scenario 3: permission control
Scenario 4: cache optimization (the first call to query the database, put the query results into the memory object, the second call, directly return from the memory object, no need to query the database)
Scenario 5: transaction management (start transaction before calling method, commit or roll back or close transaction after calling method)
Two ways of Spring AOP programming
Method 1: Spring AOP is implemented in pure Java, without special compilation process and classloader, and the target class is embedded with enhanced code by proxy during runtime (programming is very complex)
Mode 2: after Spring 2.0, it supports the third-party AOP framework (AspectJ), and implements another AOP programming (recommended)
AOP programming related terms
1. Aspect: it is a combination of notification and pointcut. Notification and pointcut jointly define the whole content about the aspect - its function, when and where to complete its function
2. Join point: the so-called join points refer to those intercepted. In spring, these points refer to methods, because spring only supports connection points of method type
3. Pointcut: the so-called pointcut refers to the definition of which join points we want to intercept. When the notification defines "what" and "when" of the cut, the pointcut defines "where"
4. Advice (notification, enhancement): the so-called notification refers to the notification that is the thing to be done after intercepting the joinpoint. Notifications are divided into pre notification, post notification, exception notification, final notification, and surround notification (functions to be completed in all aspects)
5. Target: the target object of the agent
6. Weaving: refers to the process of applying the facet to the target object to create a new proxy object. The facet is woven into the target object at the specified connection point
7. Introduction (not required to master): without modifying the class code, introduction can dynamically add some methods or fields to the class during the runtime
The underlying mechanism of AOP programming
AOP is to create proxy objects for the target. Spring AOP is based on dynamic proxy, which is based on two dynamic proxy mechanisms: JDK dynamic proxy and CGLIB dynamic proxy
Mode 1: JDK dynamic agent
JDK dynamic proxy, proxy for the interface of the target object, dynamically generate the implementation class of the interface (there must be an interface)
Key points of process
1. A proxy must be generated for the interface
2. Use Proxy object to create Proxy object for the target through newProxyInstance method.
This method receives three parameters:
(1) target object class loader
(2) interface implemented by the target object
(3) InvocationHandler after agent
3. Implement the invoke method in the InvocationHandler interface. When each method of the target object is called, the invoke will be executed
service level
//Interface (represents the target interface of the agent) public interface ICustomerService { //Preservation void save(); //query int find(); } //Implementation layer public class CustomerServiceImpl implements ICustomerService{ @Override public void save() { System.out.println("The customer saved....."); } @Override public int find() { System.out.println("The number of customer inquiries....."); return 100; } }
JDK dynamic agent factory
//General purpose for generating dynamic proxy objects for jdk public class JdkProxyFactory{ //Target target object private Object target; //Inject target target object public JdkProxyFactory(Object target) { this.target = target; } public Object getProxyObject(){ /** * Parameter 1: class loader of the target object * Parameter 2: interface implemented by the target object * Parameter 3: callback method object */ return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler(){ public Object invoke(Object proxy, Method method, Object[] args)throws Throwable { //If it is a saved method, log it if(method.getName().equals("save")){ System.out.println("Enhanced Code: write log..."); } //Target object original method execution Object object = method.invoke(target, args);//Call a method of the target object and return the target object return object; } }); } }
test method
//Objective: to use dynamic agents to enhance the original method without changing the original code. //JDK dynamic proxy: interface based (object type, interface must be implemented!) @Test public void testJdkProxy(){ //Target (target object) ICustomerService target = new CustomerServiceImpl(); //Instantiate injection target object JdkProxyFactory jdkProxyFactory = new JdkProxyFactory(target); //Get Object proxy Object: Object of subtype based on the type of interface of target Object type //The interface object must be used to de enforce ICustomerService proxy = (ICustomerService)jdkProxyFactory.getProxyObject(); //Method to call the target object proxy.save(); System.out.println("----------"); proxy.find(); }
Be careful
The object generated by JDK dynamic agent is no longer the original object
- Error:
CustomerServiceImpl proxy = (CustomerServiceImpl)jdkProxyFactory.getProxyObject();
- Correct
ICustomerService proxy = (ICustomerService)jdkProxyFactory.getProxyObject();
Mode 2: Cglib dynamic agent
Cglib is introduced to solve the problem of direct proxy of classes (generation of proxy subclasses), which can be proxy without interface
The proxy mode requires the corresponding jar package, but does not need to be imported. Because the Spring core package already contains cglib, and at the same time contains the package of asm that cglib relies on (the operation class library of dynamic bytecode)
//Classes without interfaces public class ProductService { public void save() { System.out.println("The goods are preserved....."); } public int find() { System.out.println("The quantity of the goods inquired....."); return 99; } }
Using cglib proxy
//Cglib dynamic proxy factory: used to generate cglib proxy objects public class CglibProxyFactory implements MethodInterceptor{ private Object target; //Inject proxy object public CglibProxyFactory(Object target) { this.target = target; } //Get proxy object public Object getProxyObject(){ //1. Proxy object generator (factory idea) Enhancer enhancer = new Enhancer(); // Class loader enhancer.setClassLoader(target.getClass().getClassLoader()); //2. Set two properties on the intensifier //Set target object to generate proxy object: subtype of the generated target object type enhancer.setSuperclass(target.getClass()); //Set callback method enhancer.setCallback(this); //3. Create acquisition object return enhancer.create(); } //Callback method (method of proxy object) /** * Parameter 1: proxy object * Parameter 2: method object of target object * Parameter 3: the value of the parameter of the method of the target object * Parameter 4: method object of proxy object */ public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { //If it is a saved method, log it if(method.getName().equals("save")){ System.out.println("Enhanced Code: write log..."); } //Target object original method execution //Call a method of the target object and return the target object Object object = method.invoke(target, args); return object; } }
test method
//cglib dynamic proxy: proxy objects can be generated based on classes without implementing interfaces @Test public void testCglibProxy(){ //Target target: ProductService target = new ProductService(); //Agent factory object, injection target CglibProxyFactory cglibProxyFactory = new CglibProxyFactory(target); //Get proxy //The proxy object is actually a subtype of the target object type ProductService proxy = (ProductService)cglibProxyFactory.getProxyObject(); //Method to call the proxy object proxy.save(); System.out.println("----------—"); proxy.find(); }
summary
spring generates dynamic proxy objects at runtime without special compiler
Spring AOP preferentially proxies the interface (using Jdk dynamic proxy). If the target object does not implement any interface, the class will be proxied (using cglib dynamic proxy)
Be careful
1. Creating a proxy for an interface is better than creating a proxy for a class. Because it will produce a more loosely coupled system, spring uses the JDK proxy by default. Class broker is a third-party class library that allows legacy systems or interfaces that cannot be implemented to be notified, which should be an alternative solution
2. Methods marked final cannot be notified. spring generates subclasses for the target class. Any method that needs to be notified is copied and the notification is woven in. The final method is not allowed to be overridden
3.spring only supports method connection points: it does not provide attribute access points. spring's point of view is that attribute interception breaks the encapsulation. The concept of object-oriented is that objects handle their own work, and other objects can only get results through method calls