Following the above.
Today's main study is AOP
1. What is AOP?
Aspect-Oriented Programming, aspect-oriented programming.
For example, when we go to the market to buy vegetables, in order to prevent pesticide residues in the vegetables sold by the merchants, we need to carry a calibration tester with us. Every time we buy a vegetable, we need to check it manually. When we use AOP, we only need to go to buy vegetables, AOP automatically helps us to complete the detection of pesticide residues.
In our Javabean, we need to operate a method, like adding a user. Before adding a user, we need to verify the permissions. After adding a user, we need to do a post-event logging. If we need to do this for each method, we will It will be a big project. When we don't need this permission one day, we need to delete one by one. Thinking about it, it will collapse. So have we extracted the log records during the permission checksum? AOP provides us with such a method.
Second, the benefits of using AOP
1. The logging code is separated from the real business logic code
2. The general system functions (log recording, permission verification) are highly modularized
3. The function of business logic has become more concise, only including the code of business logic
4. AOP can mix and execute system functions (logging) with business logic functions
Three, two underlying implementations of AOP
1. Dynamic proxy
1.1 What is a proxy
Principle of the proxy design pattern: wrap the original object with a proxy object, and then replace the original object with the proxy object. Any call to the original object goes through the proxy object. The proxy object decides whether and when to route method calls to the original on the object.
1.2 Static proxy
@Override public boolean update(User user) { System.out.println("Execute permission check, log record......"); return userService.update(user); }
Manually add a proxy method for each class. If there are many classes, it will be a huge project, so we use the dynamic proxy method
1.3 The benefits of dynamic proxies
We can dynamically generate a Proxy that holds the original object and implements the proxy interface while the system is running, while "implanting" our general logic (logs, permissions, etc.).
Dynamic proxies can achieve the same functions as static proxies, the only difference is that the creation of these proxies is automatic and generated when the system is running. This eliminates the need to create a proxy for each original object.
Next, let's look at two implementations of dynamic proxy: JDK dynamic proxy and CGLIB dynamic proxy
2. JDK dynamic proxy
2.1 Create maven project, guide package
<dependency> <groupId>aopalliance</groupId> <artifactId>aopalliance</artifactId> <version>1.0</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.6.8</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>4.2.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>4.2.4.RELEASE</version> </dependency>
2.2 Define the interface and implementation class
public interface UserService { public String getbyid(); public void add(); public void delete(); public void update(); public void batch(); }
public class UserServiceImpl implements UserService { @Override public void add() { System.out.println("Execute specific business logic: add..."); } @Override public String getbyid() { System.out.println("Execute specific business logic: getbyid..."); return null; } @Override public void delete() { System.out.println("Execute specific business logic: delete..."); } @Override public void update() { System.out.println("Execute specific business logic: update..."); } @Override public void batch() { System.out.println("Execute specific business logic: batch..."); } }
2.3. Define logic enhancement (aspect class: encapsulate enhancement logic)
public class SecurityAspect { //check logic public void check(){ System.out.println("Check permissions............"); } }
2.4. Create his proxy object for the original object
//create proxy object public class ProxyFactory implements InvocationHandler { // target private Object msg; public ProxyFactory(Object msg) { super(); this.msg = msg; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // Get the aspect class and perform aspect enhancement SecurityAspect securityAspect = new SecurityAspect(); securityAspect.check(); // Execute the target object method Object invoke = method.invoke(msg, args); return invoke; } // create proxy object public Object getproxy() { return Proxy.newProxyInstance(msg.getClass().getClassLoader(), msg.getClass().getInterfaces(), this); } }
2.5, create a test class
@Test public void testName2() throws Exception { UserService userService = new UserServiceImpl(); UserService user = (UserService) new ProxyFactory(userService).getproxy(); user.add(); }
2.6 Existing problems
There is a problem with using the built-in Proxy (JDK dynamic proxy) to implement dynamic proxy: the class to be proxied must implement the interface, and there is no way to complete the dynamic proxy without implementing the interface.
3. CGLIB dynamic proxy
cglib inherits the proxied class (UserServiceImpl), rewrites methods, weaves in notifications, dynamically generates bytecodes and runs them. Because of inheritance, there is no way for final classes to be dynamically proxied.
3.1 Define our target class (no need to implement the interface)
public class UserCglib { public void show(String string){ System.out.println("target class method"+string); } }
3.2. Defining our Aspects
public class UserAspct { public void writelog(){ System.out.println("I am the aspect control object"); } }
3.3. Define dynamic proxy
public class CglibPorxyFactory implements MethodInterceptor { // target class private Object msg; // logic enhancement @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy proxy) throws Throwable { //Get the interception class and execute the interception method UserAspct userAspct = new UserAspct(); userAspct.writelog(); //Get the target class and execute the target method Object invokeSuper = proxy.invokeSuper(o, objects); return invokeSuper; } //Get the proxy object public Object getproxy(Object msg) { this.msg=msg; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(msg.getClass()); enhancer.setCallback(this); Object create = enhancer.create(); return create; } }
3.4. Test class
@Test public void testName() throws Exception { UserCglib getproxy = (UserCglib) new CglibPorxyFactory().getproxy(new UserCglib()); getproxy.show("====================>Ozawa"); }
4. Terminology in AOP
Aspect: A special object whose cross-cutting logic is modularized. i.e. it is a class: like LogAspect
Advice: work that must be done in the aspect. i.e. it is a method in the class: like writeLog()
Target class (target): the object to be notified of the enhancement
Proxy class (proxy): notify the target class of the object generated after the enhancement is applied
Pointcut: The definition of the "place" in the aspect where the notification executes
JoinPoint: The execution point that matches the pointcut: such as all methods in the target class getUserId()
5. AOP is implemented based on xml configuration
1. Spring develops AOP based on xml
1.1 Create interface and implementation class
public interface UserService { public String getbyid(); public void add(); public String delete(); public void update(); public void batch(); }
public class UserServiceImpl implements UserService { @Override public void add() { System.out.println("Execute specific business logic: add..."); } @Override public String getbyid() { System.out.println("Execute specific business logic: getbyid..."); // System.out.println(1/0); return null; } @Override public String delete() { System.out.println("Execute specific business logic: delete..."); return "big data"; // System.out.println(1/0); } @Override public void update() { System.out.println("Execute specific business logic: update..."); // System.out.println(1/0); } @Override public void batch() { System.out.println("Execute specific business logic: batch..."); } }
1.2, define the aspect class
public class XmlAspect { public void beforAspect(JoinPoint jp ){ System.out.println(jp.getSignature().getName()); System.out.println("I am the front, I want to execute first.........."); } public void afterAspect(){ System.out.println("I am a post method, I want to execute it later.........."); } public void afterReturningAspect(JoinPoint jp,Object obj){ System.out.println(obj); System.out.println("I am the return method, I will execute it regardless of right or wrong.........."); } public void exceptionAspect(Exception ex){ System.out.println(ex); System.out.println("I am reporting an error, if there is an error, I will execute it.........."); } public Object aroundAspect( ProceedingJoinPoint jp ) throws Throwable{ System.out.println("I am before the surround notification................................"); Object proceed = jp.proceed(); System.out.println("I am after the surround notification................................"); return proceed; } }
1.3 Configure the target class, aspect class, and configure the core file in the Spring container
<?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:c="http://www.springframework.org/schema/c" xmlns:p="http://www.springframework.org/schema/p" 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-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd"> <!-- Register target and aspect objects --> <bean id="userserv" class="cn.itcast.dao.xml.UserServiceImpl"></bean> <bean id="xmlaspect" class="cn.itcast.dao.xml.XmlAspect"></bean> <!-- Configure spring core configuration file: configure entry point, notification, aspect--> <aop:config> <!-- Pointcut Configuration --> <aop:pointcut expression="execution(* *.add*(..))" id="atter1" /> <aop:pointcut expression="execution(* *.getbyid*(..))" id="atter2" /> <aop:pointcut expression="execution(* *.delete*(..))" id="atter3" /> <aop:pointcut expression="execution(* *.update*(..))" id="atter4" /> <aop:pointcut expression="execution(* *.batch*(..))" id="atter5" /> <!-- Aspect Configuration--> <aop:aspect ref="xmlaspect"> <!-- Pre-notification configuration--> <aop:before method="beforAspect" pointcut-ref="atter1" /> <!-- Post notification --> <aop:after method="afterAspect" pointcut-ref="atter2" /> <!-- return notification--> <aop:after-returning method="afterReturningAspect" pointcut-ref="atter3" returning="obj" /> <!-- Error notification--> <aop:after-throwing method="exceptionAspect" pointcut-ref="atter4" throwing="ex" /> <!-- Surround Notification --> <aop:around method="aroundAspect" pointcut-ref="atter5" /> </aop:aspect> </aop:config> </beans>
1.4 Test class
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext-aop-xml.xml") public class Xmltest { @Autowired//Get the target proxy object in the spring container private UserService service; @Test public void testName() throws Exception { service.add(); // service.getbyid(); // service.delete(); // service.update(); // service.batch(); } }
6. Implementation of AOP based on annotations
1. Enable spring annotation scanning and enable automatic proxy for aop annotations
<?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:c="http://www.springframework.org/schema/c" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd"> <!-- Scan annotation--> <context:component-scan base-package="cn.itcast.spring.annotation"></context:component-scan> <!-- Enable automatic proxy --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
2. Define the interface and the implementation class
public interface UserService { public String getbyid(); public void add(); public String delete(); public void update(); public void batch(); }
@Service//Place this class in the Spring container public class UserServiceImpl implements UserService { @Override public void add() { System.out.println("Execute specific business logic: add..."); } @Override public String getbyid() { System.out.println("Execute specific business logic: getbyid..."); // System.out.println(1/0); return null; } @Override public String delete() { System.out.println("Execute specific business logic: delete..."); // System.out.println(1/0); return "big data"; } @Override public void update() { System.out.println("Execute specific business logic: update..."); // System.out.println(1/0); } @Override public void batch() { System.out.println("Execute specific business logic: batch..."); } }
3. Define the aspect class
@Component @Aspect public class AspectaAnnotation { @Before(value = "execution(* *.add*(..))") public void beforAspect(JoinPoint jp ){ System.out.println(jp.getSignature().getName()); System.out.println("I am the front, I want to execute first.........."); } @After(value = "execution(* *.getbyid*(..))") public void afterAspect(){ System.out.println("I am the post method, I will execute it regardless of right or wrong.........."); } @AfterReturning(value="execution(* *.delete*(..))",returning="obj" ) public void afterReturningAspect(JoinPoint jp,Object obj){ System.out.println(obj); System.out.println("I am the return method,................................"); } @AfterThrowing(value="execution(* *.update*(..))",throwing="ex") public void exceptionAspect(Exception ex){ System.out.println(ex); System.out.println("I am reporting an error, if there is an error, I will execute it.........."); } @Around(value = "execution(* *.batch*(..))") public Object aroundAspect( ProceedingJoinPoint jp ) throws Throwable{ System.out.println("I am before the surround notification................................"); Object proceed = jp.proceed(); System.out.println("I am after the surround notification................................"); return proceed; } }
4. Test
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext-aop-annotation.xml") public class Annotationtest { @Autowired private UserService service; @Test public void testName() throws Exception { // service.add(); // service.getbyid(); // service.delete(); // service.update(); service.batch(); } }