This is the 18th day of my participation in Gwen Challenge
The concept of AOP
In the software industry, AOP for the abbreviation of Aspect Oriented Programming, meaning: section-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. Using AOP, each part of the business logic can be isolated, thus reducing the degree of coupling between each part of the business logic, improving the reusability of the program, and improving the efficiency of development. AOP is a technique that allows you to dynamically and uniformly add functionality to a program without modifying the source code through precompilation and runtime dynamic proxy implementations.
AOP mainly implements functional logging, performance statistics, security control, transaction processing, exception handling, and so on. By separating logging, performance statistics, security controls, transaction handling, exception handling, etc., from the business logic code, we hope to separate these behaviors into methods that do not guide the business logic, and thus change these behaviors without affecting the business logic code.
The main idea of AOP is summed up as horizontal repetition and vertical extraction.
Two, Spring implementation of AOP principle and the underlying implementation
Spring’s underlying implementation of AOP uses two proxy mechanisms. One is JDK dynamic proxy, the other is Cglib dynamic proxy. Let’s examine the two proxy modes.
JDK dynamic proxy
The proxied object must implement the interface to generate the proxy object. If the proxied object cannot implement the interface, the dynamic proxy technique in this way is invalid.
Next do a low-level code writing to understand.
(1) First of all, dynamic proxies in the JDK require prosted-objects to implement interfaces. We prepare an interface and an implementation class for the interface.
public interface UserDao { public void saveUser(); } public class UserDaoImpl implements UserDao {public void saveUser(){system.out.println (" saveUser "); }}Copy the code
(2) Establish a dynamic proxy class of UserDao to implement the interface InvocationHandler.
public class UserProxy implements InvocationHandler{ private UserDao userDao ; public UserProxy(UserDao userDao) { this.userDao = userDao; } public UserDao createProxy(){ UserDao userDaoProxy = (UserDao) Proxy.newProxyInstance(userDao.getClass().getClassLoader(),userDao.getClass().getInterfaces(), this); return userDaoProxy; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {system.out.println (" dynamic proxy "); Object[] args) throws Throwable {system.out.println (" dynamic proxy "); return method.invoke(userDao, args); }}Copy the code
(3) Unit test, found that the first method execution was not dynamic proxy, the second execution was dynamic proxy.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TestJunit {
@Test
public void test3(){
UserDaoImpl userDaoImpl = new UserDaoImpl();
userDaoImpl.saveUser();
UserProxy userProxy = new UserProxy(userDaoImpl);
UserDao createProxy = userProxy.createProxy();
createProxy.saveUser();
}
}
Copy the code
2. Cglib dynamic proxy
Generate proxy for some proxy objects that can not realize the interface, you can inherit proxy for any object that has not been modified by final, and its underlying application is the technology of bytecode enhancement to generate subclass objects of proxy objects. Cglib dynamic proxies cannot be used if the class is not inheritable if it is decorated with final.
(1) Create a cglib dynamic proxy object implementation interface.
public class CglibProxy implements MethodInterceptor{ private UserDaoImpl userDaoImpl; public CglibProxy(UserDaoImpl userDaoImpl) { this.userDaoImpl = userDaoImpl; } public UserDaoImpl createProxy(){ Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(UserDaoImpl.class); enhancer.setCallback(this); UserDaoImpl udi = (UserDaoImpl) enhancer.create(); return udi; } @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { Object obj = methodProxy.invokeSuper(proxy, args); System.out.println(" dynamic proxy "); return obj; }}Copy the code
(2) Conduct unit tests.
public void test4(){
UserDaoImpl userDaoImpl = new UserDaoImpl();
userDaoImpl.saveUser();
CglibProxy cglib = new CglibProxy(userDaoImpl);
UserDaoImpl userDaoImpl2 = cglib.createProxy();
userDaoImpl2.saveUser();
}
Copy the code
You can see that the first saveUser does not perform dynamic proxy, and the second does.
Conclusion: The two proxy technologies complement each other for different situations, so that any object can achieve dynamic proxy. Spring uses JDK dynamic proxy technology by default when implementing AOP. When JDK dynamic proxy technology fails, cglib dynamic proxy technology is used to ensure that the propped object can be propped normally. To use the Cglib dynamic proxy, you can configure it in the Spring configuration file.
< aop: con fi g proxy - target - class = "true" >Copy the code
Related concepts in AOP development
1. Joinpoint: All methods that can be enhanced in the target object.
2. Pointcut: Enhanced methods in the target object.
Advice: For the target object, you need to give the target object enhanced methods.
4. Target: proxied object.
Weaving: The process of applying notifications to a pointcut.
6. Proxy: An enhanced object formed after notifications are woven into the target object.
Aspect: a combination of pointcuts and notifications.
The implementation of AOP in Spring
It is introduced in two ways, one is XML configuration and the other is annotation.
1. XML configuration
(1) Implementation of Spring AOP needs to import AOP package, aspect package, AOPAlliance package, weaver package. You can find a way to get these packages in Spring Tutorial 1.
(2) Write method classes that need to be added.
Public class UserDaoImpl{public void saveUser(){system.out.println (" saveUser "); } public void deleteUser(){system.out.println (" deleteUser "); }}Copy the code
(3) Write notifications, that is, code methods that you want to add.
Public class UserAdvice{public void before(){system.out.println (" "); } public void afterReturning(){system.out.println (" returning "); } public Object around(ProceedingJoinPoint PJP) throws Throwable{system.out.println (" before executing "); Object proceed = pjp.proceed(); System.out.println(" after execution "); return proceed; } public void afterThrowException(){system.out.println (); } public void after(){system.out.println (); }}Copy the code
(4) Configure it in the Spring configuration file
<bean name = "userDaoImpl" class="com.jichi.aop.UserDaoImpl"></bean> <bean name="userAdvice" class="com.jichi.aop.UserAdvice"></bean> <aop:config> <aop:pointcut expression="execution(* com.jichi.aop.. UserDaoImpl.*(..) )" id="pc"/> <aop:aspect ref="userAdvice"> <aop:before method="before" pointcut-ref="pc"/> <aop:after-returning method="afterReturning" pointcut-ref="pc"/> <aop:around method="around" pointcut-ref="pc"/> <aop:after-throwing method="afterThrowException" pointcut-ref="pc"/> <aop:after method="after" pointcut-ref="pc"/> </aop:aspect> </aop:config>Copy the code
(5) Unit test
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TestAop {
@Resource
private UserDaoImpl userDaoImpl;
@Test
public void test1(){
userDaoImpl.saveUser();
}
}
Copy the code
The result is as follows: Weaving succeeded.
2, annotation configuration mode
(1) The same as the first method needs to import packages
(2) Write method classes that need to be added.
Public class UserDaoImpl{public void saveUser(){system.out.println (" saveUser "); } public void deleteUser(){system.out.println (" deleteUser "); }}Copy the code
(3) Write notifications, that is, code methods that you want to add.
Public class UserAdvice{public void before(){system.out.println (" "); } public void afterReturning(){system.out.println (" returning "); } public Object around(ProceedingJoinPoint PJP) throws Throwable{system.out.println (" before executing "); Object proceed = pjp.proceed(); System.out.println(" after execution "); return proceed; } public void afterThrowException(){system.out.println (); } public void after(){system.out.println (); }}Copy the code
(4) Configure in the Spring configuration file and turn on annotation AOP
<bean name = "userDaoImpl" class="com.jichi.aop.UserDaoImpl"></bean>
<bean name="userAdvice" class="com.jichi.aop.UserAdvice"></bean>
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
Copy the code
(5) Annotate the notification class with the aspect. Annotate methods accordingly
@Aspect public class UserAdvice{ @Before("execution(* com.jichi.aop.. UserDaoImpl.*(..) )") public void before(){system.out.println (" "); } @AfterReturning("execution(* com.jichi.aop.. UserDaoImpl.*(..) )") public void afterReturning(){system.out.println (" return "); } @Around("execution(* com.jichi.aop.. UserDaoImpl.*(..) )") public Object around(ProceedingJoinPoint PJP) throws Throwable{system.out.println (" before executing "); Object proceed = pjp.proceed(); System.out.println(" after execution "); return proceed; } @AfterThrowing("execution(* com.jichi.aop.. UserDaoImpl.*(..) )") public void afterThrowException(){system.out.println (" "); } @After("execution(* com.jichi.aop.. UserDaoImpl.*(..) )") public void after(){system.out.println (); }}Copy the code
Optimization method: Each method is configured with method extraction, which is bloated and can be extracted as follows
@Aspect public class UserAdvice{ @Pointcut("execution(* com.jichi.aop.. UserDaoImpl.*(..) )") public void adc(){} @before (" useradvice.adc ()") public void Before(){system.out.println (); } @afterreturning (" useraid.adc ()") public void AfterReturning(){system.out.println (" AfterReturning "); } @around (" useradvice.adc ()") public Object Around(ProceedingJoinPoint PJP) throws Throwable{system.out.println (" before executing "); Object proceed = pjp.proceed(); System.out.println(" after execution "); return proceed; } @afterthrowException (" useradvice.adc ()") public void afterThrowException(){system.out.println (" error "); } @after (" useradvice.adc ()") public void After(){system.out.println (); }}Copy the code