In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-15 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
This article mainly introduces "how to use Spring AOP tags". In daily operation, I believe many people have doubts about how to use Spring AOP tags. The editor consulted all kinds of materials and sorted out simple and easy-to-use methods of operation. I hope it will be helpful for you to answer the doubts about "how to use Spring AOP tags". Next, please follow the editor to study!
one
There is an interface Dao with three methods: insert, delete and update. Before and after insert and update are called, the milliseconds before and after the call are printed.
First, define a Dao interface:
/ * * @ author Changjie http://www.cnblogs.com/xrq730/p/7003082.html * / public interface Dao {public void insert (); public void delete (); public void update ();}
Then define an implementation class DaoImpl:
/ * * @ author Changjie http://www.cnblogs.com/xrq730/p/7003082.html * / public class DaoImpl implements Dao {@ Override public void insert () {System.out.println ("DaoImpl.insert ()");} @ Override public void delete () {System.out.println ("DaoImpl.delete ()") } @ Override public void update () {System.out.println ("DaoImpl.update ()");}}
In the most original way of writing, if I want to print the time before and after calling the insert () and update () methods, I can only define a new class package layer and deal with it before and after calling the insert () method and the update () method. The new class is named ServiceImpl and its implementation is:
/ * * @ author Changjie http://www.cnblogs.com/xrq730/p/7003082.html * / public class ServiceImpl {private Dao dao = new DaoImpl (); public void insert () {System.out.println ("insert () method start time:" + System.currentTimeMillis ()); dao.insert (); System.out.println ("insert () method end time:" + System.currentTimeMillis ()) } public void delete () {dao.delete ();} public void update () {System.out.println ("update () method start time:" + System.currentTimeMillis ()); dao.update (); System.out.println ("update () method end time:" + System.currentTimeMillis ());}}
This is the most primitive way of writing, and the shortcomings of this method are clear at a glance:
The logic of the output time before and after the method call cannot be reused. If you want to add this logic somewhere else, you have to write it again.
If Dao has other implementation classes, a new class must be added to wrap the implementation class, which will cause the number of classes to expand
Use decorator mode
Then we use the design pattern, first use the decorator pattern to see how many problems can be solved. The core of the decorator pattern is to implement the Dao interface and hold a reference to the Dao interface. I named the new class LogDao and its implementation is:
/ * * @ author Changjie http://www.cnblogs.com/xrq730/p/7003082.html * / public class LogDao implements Dao {private Dao dao; public LogDao (Dao dao) {this.dao = dao;} @ Override public void insert () {System.out.println ("insert () method start time:" + System.currentTimeMillis ()); dao.insert () System.out.println ("insert () method end time:" + System.currentTimeMillis ());} @ Override public void delete () {dao.delete ();} @ Override public void update () {System.out.println ("update () method start time:" + System.currentTimeMillis ()); dao.update () System.out.println ("update () method end time:" + System.currentTimeMillis ());}}
When using it, you can use the method of "Dao dao = new LogDao (new DaoImpl ())". The advantages of this approach are:
Transparent, to the caller, it only knows Dao, not logging.
Classes will not expand infinitely. If other implementation classes of Dao need to output logs, you only need to pass different Dao implementation classes into the constructor of LogDao.
However, this approach also has obvious disadvantages, such as:
The logic of the output log still cannot be reused.
The logic of the output log is coupled with the code. If I want to output the same time before and after the delete () method, I need to modify the LogDao
However, this approach has been greatly improved compared to the most primitive code writing.
Use proxy mode
Then we use the proxy pattern to try to implement the most primitive function, using the proxy pattern, then we will define an InvocationHandler, which I call LogInvocationHandler, and its implementation is:
/ * * @ author Changjie http://www.cnblogs.com/xrq730/p/7003082.html * / public class LogInvocationHandler implements InvocationHandler {private Object obj; public LogInvocationHandler (Object obj) {this.obj = obj;} @ Override public Object invoke (Object proxy, Method method, Object [] args) throws Throwable {String methodName = method.getName () If ("insert" .equals (methodName) | | "update" .equals (methodName)) {System.out.println (methodName + "() method start time:" + System.currentTimeMillis ()); Object result = method.invoke (obj, args); System.out.println (methodName + "() method end time:" + System.currentTimeMillis ()); return result } return method.invoke (obj, args);}}
The way to call it is simple. I write a main function:
/ * * @ author Changjie http://www.cnblogs.com/xrq730/p/7003082.html * / public static void main (String [] args) {Dao dao = new DaoImpl (); Dao proxyDao = (Dao) Proxy.newProxyInstance (LogInvocationHandler.class.getClassLoader (), new Class [] {Dao.class}, new LogInvocationHandler (dao)) in May; proxyDao.insert () System.out.println (- split line -); proxyDao.delete (); System.out.println ("- split line -"); proxyDao.update ();}
As a result, it will not be demonstrated, and the advantages of this approach are:
The logic of the output log is reused. If you want to use the logic of the output log for other interfaces, you only need to add the contents of the Class array to the second parameter of newProxyInstance.
The disadvantages of this approach are:
The dynamic proxy provided by JDK can only act as a proxy for an interface, not a class.
The code is still coupled. If you want to print the time before and after the delete method call, you have to add the judgment of the delete method to the LogInvocationHandler.
Use CGLIB
Next, take a look at how to use CGLIB. To use CGLIB, you only need to implement the MethodInterceptor interface:
/ * @ author Changjie http://www.cnblogs.com/xrq730/p/7003082.html * / public class DaoProxy implements MethodInterceptor {@ Override public Object intercept (Object object, Method method, Object [] objects, MethodProxy proxy) throws Throwable {String methodName = method.getName () If ("insert" .equals (methodName) | | "update" .equals (methodName)) {System.out.println (methodName + "() method start time:" + System.currentTimeMillis ()); proxy.invokeSuper (object, objects); System.out.println (methodName + "() method end time:" + System.currentTimeMillis ()); return object } proxy.invokeSuper (object, objects); return object;}}
The code is called as follows:
/ * * @ author Changjie http://www.cnblogs.com/xrq730/p/7003082.html * / public static void main (String [] args) {DaoProxy daoProxy = new DaoProxy (); Enhancer enhancer = new Enhancer (); enhancer.setSuperclass (DaoImpl.class); enhancer.setCallback (daoProxy); Dao dao = (DaoImpl) enhancer.create (); dao.insert () System.out.println (- split line -); dao.delete (); System.out.println ("- split line -"); dao.update ();}
Using CGLIB solves the problem that JDK's Proxy cannot act as a proxy for classes, but here is a specific problem: using decorator mode is an improvement on using native code, using Java proxy is an improvement on using decorator pattern, but using CGLIB is not an improvement on using Java proxy.
It can be said that the improvement is because using decorator mode is better than using native code, and using Java proxy is better than using decorator mode, but the comparison between Java proxy and CGLIb cannot be said to be improved, because using CGLIB is not necessarily better than using Java proxy, both have their own advantages and disadvantages. For example, the Spring framework supports both Java Proxy and CGLIB.
The code looks a little better so far, but I think there are two drawbacks:
It's a bit of a hassle to write this part of the code whether you use the Java agent or CGLIB
The coupling between the code has not been solved, for example, if you want to add this part of the logic to the delete () method, you must modify the code.
Use AOP
Finally, let's take a look at how to use AOP. First, we define a time processing class, which I call TimeHandler:
/ * * @ author Changjie http://www.cnblogs.com/xrq730/p/7003082.html * / public class TimeHandler {public void printTime (ProceedingJoinPoint pjp) {Signature signature = pjp.getSignature (); if (signature instanceof MethodSignature) {MethodSignature methodSignature = (MethodSignature) signature; Method method = methodSignature.getMethod () System.out.println (method.getName () + "() method start time:" + System.currentTimeMillis ()); try {pjp.proceed (); System.out.println (method.getName () + "() method end time:" + System.currentTimeMillis ()) } catch (Throwable e) {}
The code on line 8 and the code on line 12 print the method start time and method end execution time, respectively. I write here a little more complicated, using the aop:around method, in fact, it can also be divided into aop:before and aop:after, this depends on personal preference.
Here, the aspect method printTime itself does not need to define any parameters, but in some scenarios, you need to obtain the class and method signature of the calling method. In this case, you can define JointPoint,Spring in the printTime method to automatically inject the parameters, and you can obtain the class and method signature of the calling method through JoinPoint. Because of the aop:around I use here, make sure the method is called so that you can output time before and after the method call, so you can't use JoinPoint directly, because JoinPoint can't guarantee the method call. At this point, you can use the proceed () method of ProceedingJoinPoint,ProceedingPointPoint to guarantee the method call, but note that ProceedingJoinPoint can only be paired with aop:around. In other words, if aop:before is configured in aop.xml and the method parameter of printTime is ProceedingJoinPoint, the Spring container startup will report an error.
Next, take a look at the configuration of aop.xml:
I'm not very good at writing expression, and I don't bother to go to Baidu, so here I intercept all the methods under Dao. The test code is simple:
=
/ * *
* @ author Changjie http://www.cnblogs.com/xrq730/p/7003082.html in May
, /
Public class AopTest {
@ Test @ SuppressWarnings ("resource") public void testAop () {ApplicationContext ac = new ClassPathXmlApplicationContext ("spring/aop.xml"); Dao dao = (Dao) ac.getBean ("daoImpl"); dao.insert (); System.out.println ("- split line -"); dao.delete () System.out.println ("- split line -"); dao.update ();}} AOP summary
As a result, there will be no demonstration. Here I would like to summarize several advantages of using AOP:
Aspect content can be reused, such as TimeHandler's printTime method. Anywhere you need to print the time before and after method execution, you can use TimeHandler's printTime method.
Avoid using Proxy and CGLIB to generate agents. All the work in this area is implemented in the framework, and developers can focus on the content itself.
There is no coupling between the code and the code. If the method of interception changes, you can modify the configuration file.
Here is a picture to show the role of AOP:
Our traditional programming method is vertical programming, that is, A-> B-> C-> D goes on like this, and one logic is completed and another logic is executed. But AOP provides another way of thinking, and its function is to enhance the function of the business code without the knowledge of the business logic (that is, the business logic does not need to make any changes). There are many scenarios for this programming idea, such as transaction commit, permission detection before method execution, log printing, method call events, and so on.
Examples of AOP usage scenarios
The above example is purely for demonstration use, in order to make people better understand the role of AOP, here is an example of the actual scenario.
In the first example, we know that transactions in MyBatis do not commit automatically by default, so when programming, we must call the commit () method of SqlSession to commit transactions after adding, deleting and modifying. This is very troublesome. Let's simply write a code using AOP to help us commit transactions automatically (this code I have personally tested is available):
/ * * @ author Changjie http://www.cnblogs.com/xrq730/p/7003082.html * / public class TransactionHandler {public void commit (JoinPoint jp) {Object obj = jp.getTarget (); if (obj instanceof MailDao) {Signature signature = jp.getSignature (); if (signature instanceof MethodSignature) {SqlSession sqlSession = SqlSessionThrealLocalUtil.getSqlSession () MethodSignature methodSignature = (MethodSignature) signature; Method method = methodSignature.getMethod (); String methodName = method.getName (); if (methodName.startsWith ("insert") | | methodName.startsWith ("update") | | methodName.startsWith ("delete")) {sqlSession.commit () } sqlSession.close ();}
In this scenario, the aop tag we want to use is aop:after, that is, after the method call.
Here I have made a SqlSessionThreadLocalUtil. Every time I open a session, I put the current session SqlSession into ThreadLocal through SqlSessionThreadLocalUtil. We can see that two functions can be realized through TransactionHandler:
Automatic commit of operational transactions for insert, update and delete
Close () the SqlSession so that you don't need to close the session in the business code, because sometimes we forget to close the SqlSession when we write the business code, which may cause the expansion of the memory handle, so this section is also done.
The whole process is unknown to the business code, and the content of TransactionHandler can be fully reused in multiple scenarios.
The second example is the example of permission control. No matter from a security point of view or from a business point of view, it is impossible for us to open all requests to all users when developing a Web system, so we need to do a layer of permission control here. When you look at the role of AOP, you will certainly see that AOP can do permission control. Here I will demonstrate how to use AOP to do permission control. We know that the native Spring MVC,Java class implements the Controller interface. Based on this, the approximate code that uses AOP for permission control is as follows (this code is purely an example. The Maven project I built is a normal Java project, so it has not been verified):
/ * * @ author Changjie http://www.cnblogs.com/xrq730/p/7003082.html * / public class PermissionHandler {public void hasPermission (JoinPoint jp) throws Exception {Object obj = jp.getTarget (); if (obj instanceof Controller) {Signature signature = jp.getSignature (); MethodSignature methodSignature = (MethodSignature) signature / / obtain method signature Method method = methodSignature.getMethod (); / / obtain method parameter Object [] args = jp.getArgs (); / / ModelAndView handleRequest (HttpServletRequest request, HttpServletResponse response) throws Exception of the only method in Controller / / this method is judged by if ("handleRequest" .equals (method.getName ()) & & args.length = = 2) {Object firstArg = args [0]; if (obj instanceof HttpServletRequest) {HttpServletRequest request = (HttpServletRequest) firstArg / / get user id long userId = Long.parseLong (request.getParameter ("userId")); / / get the current request path String requestUri = request.getRequestURI () If (! PermissionUtil.hasPermission (userId, requestUri)) {throw new Exception ("No permission");}}
There is no doubt that the aop tag we are going to use in this scenario is aop:before. Here I write very simply, get the current user id and the request path, according to these two, determine whether the user has permission to access the request, you can understand the meaning.
At this point, the study on "how to use Spring AOP tags" is over. I hope to be able to solve your doubts. The collocation of theory and practice can better help you learn, go and try it! If you want to continue to learn more related knowledge, please continue to follow the website, the editor will continue to work hard to bring you more practical articles!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.