javascript
Spring学习总结二
Spring框架的代理與AOP、AspectJ
- Spring學習總結二
- 0、在理解什么是AOP之前的一些話
- 1、什么是AOP
- 2、AOP的重要概念
- 3、代理模式
- 3.1、靜態代理
- 3.2、動態代理
- 3.2.1、創建UserService接口
- 3.2.2、創建UserServiceImp類
- 3.2.3、創建MyAspect方面類
- 3.2.4、動態代理UserService的工具類
- 3.2.5、測試
- 4、cglib代理
- 4.1、導jar包
- 4.2、創建接口
- 4.3、創建實現類
- 4.4、創建方面類
- 4.5、用cglib的工具類來生成目標類
- 4.6、測試
- 5、使用spring.xml配置實現動態代理
- 5.1、導jar包
- 5.2、創建接口
- 5.3、創建目標類
- 5.4、創建方面類
- 5.5、配置spring.xml
- 5.6、測試
- 6、使用spring.xml實現AOP編程
- 6.1、在上面一個例子的基礎上加一個包
- 6.2、創建接口
- 6.3、創建實現類
- 6.4、創建方面類
- 6.5、配置spring.xml
- 6.6、測試
- 7、使用AspectJ配置spring.xml實現AOP編程
- 7.1、導包
- 7.2、創建接口
- 7.3、創建實現類
- 7.4、創建MyAspect類
- 7.5、編寫spring.xml
- 7.6、測試
- 8、使用注解的AspectJ
- 8.1、導包
- 8.2、創建接口
- 8.3、創建實現類
- 8.4、創建MyAcpect
- 8.5、編寫spring.xml
- 8.6、測試
Spring學習總結二
今天的主要內容就是AOP:
0、在理解什么是AOP之前的一些話
下面1、2兩點都是我百度上抄的,說實話,我是不太能說出這么精準的術語來。
AOP,通俗來說就是在執行特定的方法前或者后,去做"某些事情"(比如:轉賬前需要將設置事務,轉賬"成功"后需要提交事務)。
我們將尺度放大!有一些業務經常需要換一些功能。而我們不想再去改項目的硬編碼,從而有了AOP,或者是說,我想通過xml配置來動態的增加以及減少一些功能,這時候AOP就可以大顯身手了。
如何學好AOP?
先訓練,再看概念!理清楚思路,你將對AOP的概念讀上幾遍。
1、什么是AOP
AOP: (Aspect Oriented Programming) 面向切面編程。是目前軟件開發中的一個熱點,也是Spring框架中容。利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程序的可重用性,同時提高了開發的效率。主要的功能是:日志記錄,性能統計,安全控制,事務處理,異常處理等等。
AOP、OOP在字面上雖然非常類似,但卻是面向不同領域的兩種設計思想。OOP(面向對象編程)針對業務處理過程的實體及其屬性和行為進行抽象封裝,以獲得更加清晰高效的邏輯單元劃分。 而AOP則是針對業務處理過程中的切面進行提取,它所面對的是處理過程中的某個步驟或階段,以獲得邏輯過程中各部分之間低耦合性的隔離效果。這兩種設計思想在目標上有著本質的差異。
舉個簡單的例子,對于“雇員”這樣一個業務實體進行封裝,自然是OOP的任務,我們可以為其建立一個“Employee”類,并將“雇員”相關的屬性和行為封裝其中。而用AOP設計思想對“雇員”進行封裝將無從談起。
同樣,對于“權限檢查”這一動作片斷進行劃分,則是AOP的目標領域。而通過OOP對一個動作進行封裝,則有點不倫不類。 換而言之,OOP面向名詞領域,AOP面向動詞領域。
總之,AOP可以通過預編譯方式和運行期動態代理實現在不修改源代碼的情況下給程序動態統一添加功能的一種技術。
2、AOP的重要概念
實現AOP的技術,主要分為兩大類:一是采用動態代理技術,利用截取消息的方式,對該消息進行裝飾,以取代原有對象行為的執行;二是采用靜態織入的方式,引入特定的語法創建“方面”,從而使得編譯器可以在編譯期間織入有關“方面”的代碼。然而殊途同歸,實現AOP的技術特性卻是相同的,分別為:
上述的技術特性組成了基本的AOP技術,大多數AOP工具均實現了這些技術。它們也可以是研究AOP技術的基本術語。
3、代理模式
說到代理模式,我們就需要說到下面兩點:
3.1、靜態代理
這里就不寫靜態代理的代碼了。自己百度去看,主要的是以下3個點:
3.2、動態代理
需要做的事情就5步:
3.2.1、創建UserService接口
package com.csa.service; public interface UserService {public void addUser();public void updateUser();public void deleteUser(); }3.2.2、創建UserServiceImp類
package com.csa.service.Imp; import com.csa.service.UserService; public class UserServiceImp implements UserService{@Overridepublic void addUser() {// TODO Auto-generated method stubSystem.out.println("add User to ...");}@Overridepublic void updateUser() {// TODO Auto-generated method stubSystem.out.println("update User to ...");}@Overridepublic void deleteUser() {// TODO Auto-generated method stubSystem.out.println("delete User to ...");}}3.2.3、創建MyAspect方面類
package com.csa.aspect; public class MyAspect {public void before(){System.out.println("之前");}public void after(){System.out.println("之后");} }3.2.4、動態代理UserService的工具類
動態代理步驟:
想了解更多的可以看這篇代理模式深入理解
package com.csa.factory; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import com.csa.aspect.MyAspect; import com.csa.service.UserService; import com.csa.service.Imp.UserServiceImp; public class MyBeanFactory {public static UserService createService() {// 1. 目標類UserService userService = new UserServiceImp();// 2. 切面類MyAspect myAspect = new MyAspect();// 3. 代理類UserService proxyService = (UserService) Proxy.newProxyInstance(MyBeanFactory.class.getClassLoader(),userService.getClass().getInterfaces(), new InvocationHandler() {public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// TODO Auto-generated method stubmyAspect.before();Object obj = method.invoke(userService,args);myAspect.after();return obj;}});return proxyService;} }3.2.5、測試
package com.csa.Test; import org.junit.Test; import com.csa.factory.MyBeanFactory; import com.csa.service.UserService; public class TestJDK {@Testpublic void demo(){UserService userService = MyBeanFactory.createService();userService.addUser();userService.updateUser();userService.deleteUser();}}測試結果:
4、cglib代理
分6步完成:
4.1、導jar包
spring各個版本官方下載地址
4.2、創建接口
(與上面動態代理的一樣)
4.3、創建實現類
(與上面動態代理的一樣)
4.4、創建方面類
(與上面動態代理的一樣)
4.5、用cglib的工具類來生成目標類
package com.csa.factory;import java.lang.reflect.Method;import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy;import com.csa.aspect.MyAspect; import com.csa.service.UserService; import com.csa.service.Imp.UserServiceImp;public class MyBeanFactory {public static UserService createService() {// 1. 目標類UserService userService = new UserServiceImp();// 2. 切面類MyAspect myAspect = new MyAspect();// 3. 代理類// 3.1 核心類Enhancer enhancer = new Enhancer();// 3.2 確定父類enhancer.setSuperclass(userService.getClass());// 3.3 設置回調函數enhancer.setCallback(new MethodInterceptor() {@Overridepublic Object intercept(Object proxy, Method method, Object[] args,MethodProxy methodProxy) throws Throwable {// TODO Auto-generated method stubmyAspect.before();Object obj = method.invoke(userService, args);myAspect.after();return obj;}});UserServiceImp proxyService = (UserServiceImp) enhancer.create();return proxyService;} }4.6、測試
package com.csa.Test; import org.junit.Test; import com.csa.factory.MyBeanFactory; import com.csa.service.UserService; public class TestCGLIB {@Testpublic void demo(){UserService userService = MyBeanFactory.createService();userService.addUser();userService.updateUser();userService.deleteUser();}}測試結果:
5、使用spring.xml配置實現動態代理
分下面6個步驟:
5.1、導jar包
Spring下載地址
commons logging下載地址
aopalliance下載地址
最后導入的包是如下(簡稱為:4+1、aop聯盟):
5.2、創建接口
(與動態代理的一樣)
5.3、創建目標類
(與動態代理的一樣)
5.4、創建方面類
需要做兩件事:
所有的接口:
5.5、配置spring.xml
注意,我的spring.xml在src的config包下:
spring.xml配置代碼:
5.6、測試
package com.csa.Test; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;import com.csa.service.UserService;public class TestAOP {@Testpublic void demo(){String xmlPath = "config/spring.xml";ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);UserService userService = (UserService) applicationContext.getBean("proxyServiceId");userService.addUser();userService.updateUser();userService.deleteUser();}}測試結果:
6、使用spring.xml實現AOP編程
下面的幾個步驟:
6.1、在上面一個例子的基礎上加一個包
AspectJ Weaver包下載地址
最后的包是:
6.2、創建接口
(與動態代理的一樣)
6.3、創建實現類
(與動態代理的一樣)
6.4、創建方面類
(與上一個例子的一樣)
6.5、配置spring.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 http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"><!-- 1. 目標類 --><bean id="userServiceId" class="com.csa.service.Imp.UserServiceImp"></bean><!-- 2. 切面類 --><bean id="myAspectId" class="com.csa.aspect.MyAspect"></bean><!-- 3. aop編程 --><!-- 簡單來說呢,就是連接點:是"所有需要增加某一個特定功能的方法集合"織入:就是將某個有特定處理功能的類,加到"連接點"!--><aop:config proxy-target-class="true"><!-- 這里涉及得到一個表達式的問題,我給個超鏈接,自己看吧 --><!-- 下面是一個連接點,這里的表達式就是為了告訴spring,哪些方法需要被加以處理! --><aop:pointcut expression="execution(* com.csa.service..*(..))" id="myPointcut"/><!-- 下面就是我們的切面類,切面類會被"織入"到連接點 --><aop:advisor advice-ref="myAspectId" pointcut-ref="myPointcut"/></aop:config></beans>6.6、測試
package com.csa.Test; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;import com.csa.service.UserService;public class TestAOP {@Testpublic void demo(){String xmlPath = "config/spring.xml";ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);UserService userService = (UserService) applicationContext.getBean("userServiceId");userService.addUser();userService.updateUser();userService.deleteUser();}}測試結果:
7、使用AspectJ配置spring.xml實現AOP編程
分6步:
7.1、導包
在上一個例子的基礎上導入下面這個包!在spring的壓縮包下可以找到!
7.2、創建接口
不變
7.3、創建實現類
要加一個除零異常
package com.csa.service.Imp; import com.csa.service.UserService; public class UserServiceImp implements UserService {@Overridepublic void addUser() {System.out.println("addUser to ...");}@Overridepublic void updateUser() {int i = 1/0;System.out.println("updateUser to ...");}@Overridepublic void deleteUser() {System.out.println("deleteUser to ...");}}7.4、創建MyAspect類
以下是所有AOP的通知了!
package com.csa.aspect; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; public class MyAspect {/*** 前置* * @param joinPoint* 連接點*/public void myBefore(JoinPoint joinPoint) {System.out.println("前置通知: " + joinPoint.getSignature().getName());}/*** 后置* * @param joinPoint* 連接點*/public void myAfter(JoinPoint joinPoint) {System.out.println("后置通知: " + joinPoint.getSignature().getName());}/*** 環繞通知* * @param proceedingJoinPoint* 連接點* @return 返回被代理方法的具體返回值* @throws Throwable* proceedingJoinPoint.proceed()方法執行拋出的異常*/public Object myAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {System.out.println("前:" + proceedingJoinPoint.getSignature().getName());Object obj = proceedingJoinPoint.proceed();System.out.println("后:" + proceedingJoinPoint.getSignature().getName());return obj;}/*** 異常通知* * @param joinPoint* 連接點* @param e* 被代理方法執行出現異常*/public void myThrowing(JoinPoint joinPoint, Throwable e) {System.out.println("異常通知:" + joinPoint.getSignature().getName() + "\r\n異常類型:" + e.getMessage());}/*** 后置通知* * @param joinPoint* 連接點* @param ret被代理方法的具體返回值*/public void myReturning(JoinPoint joinPoint, Object ret) {System.out.println("后置通知:" + joinPoint.getSignature().getName() + "\r\n返回值:" + ret);}}7.5、編寫spring.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 http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"><!-- 目標類 --><bean id="userServiceId" class="com.csa.service.Imp.UserServiceImp"></bean><!-- 切面類 --><bean id="myAspectId" class="com.csa.aspect.MyAspect"></bean><aop:config><!-- 注意是在這個標簽下,直接引用了某個切面類 --><aop:aspect ref="myAspectId"><!-- 在這個標簽的體中間寫"通知"和"被通知的方法集合" --><!-- 連接點--><aop:pointcut expression="execution(* com.csa.service..*(..) )" id="myPointcut"/><!-- 前置通知<aop:before method="myBefore" pointcut-ref="myPointcut"/>--><!-- 后置通知<aop:after method="myAfter" pointcut-ref="myPointcut"/>--><!-- 環繞通知<aop:around method="myAround" pointcut-ref="myPointcut"/>--><!--異常通知--><aop:after-throwing method="myThrowing" pointcut-ref="myPointcut" throwing="e"/><!--后置通知<aop:after-returning method="myReturning" pointcut-ref="myPointcut" returning="ret"/>--><!-- jdk1.8 最好別使用 spring3.*.*系列 --></aop:aspect></aop:config> </beans>7.6、測試
package com.csa.test; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.csa.service.UserService; public class TestAspectJ {@Testpublic void demo() {String xmlPath = "config/spring.xml";ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);UserService userService = (UserService) applicationContext.getBean("userServiceId");userService.addUser();userService.updateUser();userService.deleteUser();} }測試結果:
8、使用注解的AspectJ
分6個步驟:
8.1、導包
與上一個例子的包一樣,沒有改變!
8.2、創建接口
沒變
8.3、創建實現類
與上一個AspectJ的例子一樣!
8.4、創建MyAcpect
package com.csa.aspect;import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component;@Component @Aspect public class MyAspect {/*** 連接點*/@Pointcut(value="execution(* com.csa.service..*(..) )")private void myPointcut() {}/*** 前置* * @param joinPoint* 連接點*/@Before(value="myPointcut()")public void myBefore(JoinPoint joinPoint) {System.out.println("前置通知: " + joinPoint.getSignature().getName());}/*** 后置* * @param joinPoint* 連接點*/@After(value="myPointcut()")public void myAfter(JoinPoint joinPoint) {System.out.println("后置通知: " + joinPoint.getSignature().getName());}/*** 環繞通知* * @param proceedingJoinPoint* 連接點* @return 返回被代理方法的具體返回值* @throws Throwable* proceedingJoinPoint.proceed()方法執行拋出的異常*/@Around(value="myPointcut()")public Object myAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {System.out.println("前:" + proceedingJoinPoint.getSignature().getName());Object obj = proceedingJoinPoint.proceed();System.out.println("后:" + proceedingJoinPoint.getSignature().getName());return obj;}/*** 異常通知* * @param joinPoint* 連接點* @param e* 被代理方法執行出現異常*/@AfterThrowing(value="myPointcut()",throwing="e")public void myThrowing(JoinPoint joinPoint, Throwable e) {System.out.println("異常通知:" + joinPoint.getSignature().getName() + "\r\n異常類型:" + e.getMessage());}/*** 后置通知* * @param joinPoint* 連接點* @param ret被代理方法的具體返回值*/@AfterReturning(value="myPointcut()",returning="ret")public void myReturning(JoinPoint joinPoint, Object ret) {System.out.println("后置通知:" + joinPoint.getSignature().getName() + "\r\n返回值:" + ret);}}8.5、編寫spring.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: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.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><!-- 掃描 注解類 --><context:component-scan base-package="com.csa"></context:component-scan><!-- 確定 aop注解生效 --><aop:aspectj-autoproxy ></aop:aspectj-autoproxy></beans>8.6、測試
package com.csa.test; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.csa.service.UserService; public class TestAspectJ {@Testpublic void demo() {String xmlPath = "config/spring.xml";ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);UserService userService = (UserService) applicationContext.getBean("userServiceId");userService.addUser();userService.updateUser();userService.deleteUser();} }測試結果:
總結
以上是生活随笔為你收集整理的Spring学习总结二的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2020年中国住宿业市场网络口碑报告
- 下一篇: Spring学习总结三