目錄
- AOP
- 概念
- 代理模式引出
- AOP實現方式
- xml方式實現
- 注解方式實現
AOP
概念
事務管理:比如可以抽取try catch的重復代碼
日志監控:比如業務邏輯前后打印關于當前訂單數量的日志,了解業務做了什么
性能監控:比如業務前后打印時間,相減可查看業務跑完所需時間
代理模式引出
用aop實現擴展功能,
aop用代理模式實現,但是代理模式里的擴展功能還是需要我們自己寫,
靜態代理:相當于一個中介只代理一個固定的房東的房源,基本不用
動態代理:默認沒有,使用的時候動態生成
AOP:以上大方向
SpringAOP:AOP的spring實現方式,用動態代理方式實現。它的實現方式又有兩種:jdk,CGLIB,spring自動選擇用其中哪種方式,代理類自動生成也不用管,有接口的時候默認使用jdk,沒有的時候用cglib(第三方jar包),現在一般service都有接口
AOP實現方式
xml方式實現
1.編寫TxManager用來提供業務邏輯外的擴展功能 - 如事務管理
/*我們自己的擴展功能*/
public class TxManager {public void open (){System.out.println("開啟事務");}public void commit (){System.out.println("提交事務");}public void rollback(Throwable e){e.printStackTrace();//處理異常System.out.println("回滾事務");}public void close(){System.out.println("關閉事務");}public void around(ProceedingJoinPoint point){try {open();point.proceed();//執行真正的業務commit();} catch (Throwable e) {e.printStackTrace();rollback(e);} finally {close();}}
}
2.準備xmlAOP環境,在Spring配置文件中引入頭支持以支持aop標簽
SpringTest-Context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"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">
3.配置的三要素
何時,如在業務的執行前、后、catch
何地,指的是在哪一個方法
做什么,執行我們自定義擴展業務類的方法
面向切面編程,面向擴展功能編程
其他
spring通過動態代理實現aop,配置aop后只能注入接口,通過接口找到被引用的代理類,Spring容器中就只有代理類沒有實現類,
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration//回到當前類的包下 查找當前類名-Context.xml的配置文件
public class SpringTest {@AutowiredIUserService userService;@Testpublic void testUser(){System.out.println(userService.getClass());}
}
SpringTest-Context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"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="userService" class="cn.itsource._03aopxml.service.impl.UserServiceImpl"/><bean id="departmentService" class="cn.itsource._03aopxml.service.impl.DepartmentServiceImpl"/><!--將擴展功能交給Spring容器管理,方便AOP使用--><bean id="txManager" class="cn.itsource._03aopxml.TxManager"/><!--SpringAOP的核心配置--><aop:config><!--配置切點 配置何地 ==在哪一個方法執行expression:表達式 通過表達式,我們找在哪一個方法執行第一個*:任意返回值I*Service:所有以I開頭 Service結尾的類(里面的所有方法都加上事物)第三個*:任意方法save(..):任意參數--><!--execution(* cn.itsource._03aopxml.service.impl.UserServiceImpl.save(..))execution(* cn.itsource._03aopxml.service.impl.UserServiceImpl.*(..))--><aop:pointcut id="txPoint" expression="execution(* cn.itsource._03aopxml.service.I*Service.*(..))"/><!--配置切面 --><aop:aspect ref="txManager"><!--配置前置通知 配置何時做什么--><!--<aop:before method="open" pointcut-ref="txPoint"/>--><!--配置后置通知--><!--<aop:after-returning method="commit" pointcut-ref="txPoint"/>--><!--配置異常通知--><!--<aop:after-throwing method="rollback" pointcut-ref="txPoint" throwing="e"/>--><!--配置最終通知--><!--<aop:after method="close" pointcut-ref="txPoint"/>--><!--配置環繞通知 環繞通知一行頂上面四行--><aop:around method="around" pointcut-ref="txPoint"/></aop:aspect></aop:config>
</beans>
測試
詳細見工程代碼
注解方式實現
A 引入容器掃描頭 Spring AOP
SpringTest-Context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:context="http://www.springframework.org/schema/context"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"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"><!--開啟Spring注解掃描--><context:component-scan base-package="cn.itsource._04aopanno"/><!--開啟SpringAOP 注解掃描--><aop:aspectj-autoproxy/></beans>
后面的幾步,都是在TxManager中完成
B 將擴展業務交給容器管理 @Component
C 申明pointcut,@Pointcut,需要提供一個空方法
D 配置各種通知
只用@Around環繞通知,其他四種通知不能確定執行順序,
/*我們自己的擴展功能*/
@Component //組件 把當前類交給Spring容器管理
@Aspect //== <aop:aspect ref="txManager"> 配置切面
public class TxManager {//配置切點 == <aop:pointcut id="txPoint"@Pointcut("execution(* cn.itsource._04aopanno.service.I*Service.*(..))")public void txPoint(){/*這個方法指明在業務類中的每個方法*/}/*配置前置通知*//*@Before("txPoint()")*/public void open (){System.out.println("開啟事物");}/*@AfterReturning("txPoint()")*/public void commit (){System.out.println("提交事物");}/*@AfterThrowing(value = "txPoint()", throwing = "e")*/public void rollback(Throwable e){e.printStackTrace();//處理異常System.out.println("回滾事務");}/*@After("txPoint()")*/public void close(){System.out.println("關閉事物");}@Around("txPoint()")public void around(ProceedingJoinPoint point){try {open();point.proceed();//執行真正的業務commit();} catch (Throwable e) {e.printStackTrace();rollback(e);} finally {close();}}
}
測試
詳細見工程代碼