1, Agent mode
The bottom layer of spring AOP
Agent mode classification:
- Static proxy
- Dynamic agent
Benefits of agent mode:
- It can make the operation of real roles more pure, without paying attention to some public businesses
- The public business is handed over to the agent role, which realizes the division of business
- When the public business is expanded, it is convenient for centralized management
Disadvantages:
- A real role will produce an agent role, the amount of code will double, and the development efficiency will be low
1. Static agent
Abstract role: interface or abstract class
//Rent a house public interface Rent { void rent(); }
Real role: the role represented
//landlord or landlady public class HouseEast implements Rent{ public void rent() { System.out.println("The landlord wants to rent the house"); } }
Proxy role: represents the real role. After proxy, there will be some additional operations
package com.shy.demo01; public class Proxy implements Rent{ private HouseEast houseEast; public Proxy(){} public Proxy(HouseEast houseEast){ this.houseEast = houseEast; } public void rent() { lookHouse(); houseEast.rent(); money(); } //House viewing public void lookHouse(){ System.out.println("The agent will show you the house!"); } //charge public void money(){ System.out.println("Close 1 w!"); } }
Client: the person who accesses the proxy object
public class Client { @Test public void test(){ //The landlord wants to rent the house HouseEast h = new HouseEast(); //Agents and intermediaries help landlords rent houses. Intermediaries generally have ancillary operations Proxy proxy = new Proxy(h); //You don't have to face the landlord and rent a house directly from an intermediary proxy.rent(); } }
Once more:
UserService interface
package com.shy.demo02; //Addition, deletion, modification and query of users public interface UserService { void add(); void delete(); void update(); void query(); }
We need to add and delete these real objects
package com.shy.demo02; public class UserServiceImpl implements UserService{ public void add() { System.out.println("Added a user"); } public void delete() { System.out.println("A user was deleted"); } public void update() { System.out.println("Modified a user"); } public void query() { System.out.println("Queried a user"); } }
Add a logging function and set the agent class
package com.shy.demo02; public class UserServiceProxy implements UserService{ private UserServiceImpl userService; public void setUserService(UserServiceImpl userService) { this.userService = userService; } public void add() { log("add"); userService.add(); } public void delete() { log("delete"); userService.delete(); } public void update() { log("update"); userService.update(); } public void query() { log("query"); userService.query(); } public void log(String msg){ System.out.println("[debug]Used"+msg+"method"); } }
Test:
package com.shy.demo02; import org.junit.Test; public class Client { @Test public void test(){ UserServiceImpl u = new UserServiceImpl(); UserServiceProxy proxy = new UserServiceProxy(); proxy.setUserService(u); proxy.add(); } }
2, Dynamic agent
The bottom layer is reflection
Dynamic agents have the same role as static agents
The agent class of dynamic agent is generated dynamically, which is not written directly by us!
Dynamic agents are divided into two categories: interface based dynamic agents and class based dynamic agents
- Interface based: JDK dynamic agent
- Class based: cglib
- java bytecode implementation: javassist
Two classes need to be understood: Proxy proxy, InvocationHandler and call handler
InvocationHandler
Benefits of dynamic agents
- It can make the operation of real roles more pure, without paying attention to some public businesses
- The public business is handed over to the agent role, which realizes the division of business
- When the public business is expanded, it is convenient for centralized management
- A dynamic agent class is an interface, which is generally the corresponding type of business
- A dynamic proxy class can proxy multiple classes as long as it implements the same interface
Code implementation:
1. Abstract role
package com.shy.demo03; //Rent a house public interface Rent { void rent(); }
2. Real role
package com.shy.demo03; //landlord or landlady public class HouseEast implements Rent { public void rent() { System.out.println("The landlord wants to rent the house"); } }
3. Agent role
package com.shy.demo03; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; //Use this class to automatically generate proxy classes public class ProxyInvocationHandler implements InvocationHandler { //Proxy interface private Rent rent; public void setRent(Rent rent) { this.rent = rent; } //Generated proxy class public Object getProxy(){ return Proxy.newProxyInstance(this.getClass().getClassLoader(), rent.getClass().getInterfaces(),this); } //Process the proxy instance and return the result public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //The essence of dynamic agent is reflection c(); Object result = method.invoke(rent, args); s(); return result; } public void c(){ System.out.println("see"); } public void s(){ System.out.println("money"); } }
4. Tenant
package com.shy.demo03; import org.junit.Test; public class Client { @Test public void test(){ //Real role HouseEast houseEast = new HouseEast(); //Agent role, not now ProxyInvocationHandler pih = new ProxyInvocationHandler(); //Handle the interface object we want to call by calling the program processing role pih.setRent(houseEast); Rent proxy = (Rent) pih.getProxy();//This proxy is dynamically generated proxy.rent(); } }
A dynamic agent generally represents a certain type of business. A dynamic agent can represent multiple classes, and the agent is the interface!
We can also write a general dynamic proxy implementation class! All proxy objects can be set to Object!
package com.shy.demo04; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; //Use this class to automatically generate proxy classes public class ProxyInvocationHandler implements InvocationHandler { //Proxy interface private Object target; public void setTarget(Object target) { this.target = target; } //Generated proxy class public Object getProxy(){ return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(),this); } //Process the proxy instance and return the result public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //The essence of dynamic agent is reflection log(method.getName()); Object result = method.invoke(target, args); return result; } public void log(String msg){ System.out.println("Yes"+msg+"method"); } }
Test:
package com.shy.demo04; import com.shy.demo02.UserService; import com.shy.demo02.UserServiceImpl; import org.junit.Test; public class Client { @Test public void test(){ //Real role UserServiceImpl userService = new UserServiceImpl(); //delegable role ProxyInvocationHandler pih = new ProxyInvocationHandler(); pih.setTarget(userService);//Sets the object to proxy //Dynamically generate proxy classes UserService proxy = (UserService) pih.getProxy(); proxy.add(); } }
3, AOP
It is a technology to realize the unified maintenance of program functions through precompiled mode and dynamic agent during operation. AOP is the continuation of OOP, a hot spot in software development, an important content of Spring framework and a derivative paradigm of functional programming. AOP can isolate all parts of business logic, so as to reduce the coupling between all parts of business logic, improve the reusability of programs, and improve the efficiency of development.
Provide declarative transactions; Allows you to customize the cut plane
Crosscutting concerns: methods or functions that span multiple modules of an application. That is, the part that has nothing to do with our business logic, but we need to focus on is crosscutting concerns. Such as log, security, cache, transaction and so on
ASPECT: a special object whose crosscutting concerns are modularized. That is, it is a class.
Advice: work that must be completed in all aspects. That is, it is a method in a class.
Target: the notified object.
Proxy: an object created after notification is applied to the target object.
PointCut: the definition of the "place" where the aspect notification is executed.
JointPoint: the execution point that matches the pointcut.
Aop adds new functions without changing the original code
1. Use Spring to implement AOP
To use AOP weaving, you need to import a dependency package
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.4</version> </dependency>
Method 1: use the API interface of Spring
Method 2: use user-defined classes to implement AOP [mainly section definition]
Method 3: implement with annotation
Example: (three methods are put together here, with notes)
1. Write business interface and implementation class
package com.shy.service; public interface UserService { void add(); void delete(); void update(); void query(); }
package com.shy.service; public class UserServiceImpl implements UserService{ public void add() { System.out.println("Added a user"); } public void delete() { System.out.println("A user was deleted"); } public void update() { System.out.println("Modified a user"); } public void query() { System.out.println("Queried a user"); } }
2. Write two enhancement classes, one pre enhancement and one post enhancement
Pre enhancement:
package com.shy.log; import org.springframework.aop.MethodBeforeAdvice; import java.lang.reflect.Method; public class log implements MethodBeforeAdvice { //Method: the method of the target object to execute //args: parameter //Target: target object public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println(target.getClass().getName()+"of"+method.getName()+"Executed"); } }
Post enhancement:
package com.shy.log; import org.springframework.aop.AfterReturningAdvice; import java.lang.reflect.Method; public class AfterLog implements AfterReturningAdvice { //returnValue: return value public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { System.out.println("Yes"+method.getName()+"The return value result is:"+returnValue); } }
3. The second method: a custom cut in class
package com.shy.diy; public class DiyPointCut { public void before(){ System.out.println("Before method execution"); } public void after(){ System.out.println("After method execution"); } }
4. The third way: write an enhanced class implemented by annotation
package com.shy.diy; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; //Implementing AOP with annotations //Mark that this class is a facet @Aspect public class AnnotationPointCut { @Before("execution(* com.shy.service.UserServiceImpl.*(..))") public void before(){ System.out.println("Before method execution"); } @After("execution(* com.shy.service.UserServiceImpl.*(..))") public void after(){ System.out.println("After method execution"); } //In surround enhancement, you can give a parameter to represent the entry point we want to obtain processing. Let's play @Around("execution(* com.shy.service.UserServiceImpl.*(..))") public void around(ProceedingJoinPoint pj) throws Throwable{ System.out.println("Surround front"); Object proceed = pj.proceed(); System.out.println("After surround"); } }
5. In ApplicationContext Register in XML
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <!--register bean--> <bean id="userService" class="com.shy.service.UserServiceImpl"/> <bean id="log" class="com.shy.log.log"/> <bean id="afterLog" class="com.shy.log.AfterLog"/> <!--Method 1: use native Spring API Interface--> <!--to configure aop Import required aop Constraints of--> <!--<aop:config> <!–breakthrough point,expression:expression, expression(Where to execute * * * ...)–> <aop:pointcut id="pointcut" expression="execution(* com.shy.service.UserServiceImpl.*(..))"/> <!–Execute wrap–> <aop:advisor advice-ref="log" pointcut-ref="pointcut"/> <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/> </aop:config>--> <!--Method 2: use custom class to implement AOP--> <!--<bean id="diy" class="com.shy.diy.DiyPointCut"/> <aop:config> <!–Custom section, ref:Referenced class–> <aop:aspect ref="diy"> <!–breakthrough point–> <aop:pointcut id="point" expression="execution(* com.shy.service.UserServiceImpl.*(..))"/> <!–notice–> <aop:before method="before" pointcut-ref="point"/> <aop:after method="after" pointcut-ref="point"/> </aop:aspect> </aop:config>--> <!--Method 3: implement with annotation--> <bean id="annotationPointCut" class="com.shy.diy.AnnotationPointCut"/> <!--Enable annotation support--> <aop:aspectj-autoproxy/> </beans>
6. Test
import com.shy.service.UserService; import com.shy.service.UserServiceImpl; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MyTest1 { @Test public void test(){ ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //Dynamic proxy is the interface UserService userService = (UserService) context.getBean("userService"); userService.delete(); } }
aop:aspectj-autoproxy:
Through the < aop: aspectJ AutoProxy / > declaration of the aop namespace, automatically create a proxy for those bean s in the spring container that configure the @ aspectJ aspect and weave it into the aspect. Of course, spring still uses AnnotationAwareAspectJAutoProxyCreator internally to create automatic proxy, but the specific implementation details have been hidden by < aop: aspectJ AutoProxy / >
< AOP: AspectJ AutoProxy / > has a proxy target class attribute, which is false by default, indicating that jdk dynamic proxy is used to weave enhancement. When it is configured as < AOP: AspectJ AutoProxy proxy target class = "true" / > it indicates that CGLib dynamic proxy technology is used to weave enhancement. However, even if proxy target class is set to false, if the target class does not declare an interface, spring will automatically use CGLib dynamic proxy.
Spring's Aop combines public business (logging, security, etc.) with domain business. When implementing domain business, public business will be added Realize the reuse of public business The domain business is more pure. The program ape focuses on the domain business, and its essence is dynamic agent