1、簡單的spring實現(annotation方式)spring
bean類express
package hello; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class HelloWorld { private String Msg; public void Hello() { System.out.println("Hello:" + Msg); } @Bean(name = "helloworldbean") public HelloWorld helloWorldBean() { HelloWorld hw = new HelloWorld(); hw.Msg = "How are you ?"; return hw; } }
測試類:segmentfault
package hello; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class TestHelloWorld { /** * @param args */ private static ApplicationContext ctx; public static void main(String[] args) { // TODO 自動生成的方法存根 ctx = new AnnotationConfigApplicationContext(HelloWorld.class); HelloWorld helloWorld = (HelloWorld) ctx.getBean("helloworldbean"); helloWorld.Hello(); } }
運行結果:app
2017-10-24 00:34:15 [org.springframework.context.annotation.AnnotationConfigApplicationContext]-[INFO] Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@12bb4df8: startup date [Tue Oct 24 00:34:15 CST 2017]; root of context hierarchy Hello:How are you ?
(xml方式)模塊化
bean類函數
package com.hello; public class XmlHello { private String name; public void setName(String name) { this.name = name; } public void printHello() { System.out.println("Spring : Hello ! " + name); } }
xml配置文件applicationContext.xml(放在包com.hello下)測試
<beans xmlns="http://www.springframework.org/schema/beans" 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-4.3.xsd"> <bean id="helloBean" class="com.hello.XmlHello"> <property name="name" value="Yiibai" /> </bean> </beans>
測試類:this
package com.hello; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class AppXmlHello { /** * @param args */ private static ApplicationContext ctx; public static void main(String[] args) { // TODO 自動生成的方法存根 ctx = new ClassPathXmlApplicationContext( "com/hello/applicationContext.xml"); XmlHello helloWorld = (XmlHello) ctx.getBean("helloBean"); helloWorld.printHello();; } }
2、註解方式實現aop(須要導入aspectjrt-1.8.11.jar,aspectjweaver-1.8.11.jar ):spa
package hello; import org.aspectj.lang.annotation.AfterReturning; 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 HelloAop { // 聲明切點 @Pointcut("execution(* *.Hello())") public void pointcut() { } @Before("pointcut()") public void beforepoint() { System.out.println("接下去調用Hello()......"); } @AfterReturning("pointcut()") public void afterhello() { System.out.println("函數Hello()執行結束......"); } }
bean類HelloWorld(@Configuration後)加上:代理
@ComponentScan @EnableAspectJAutoProxy
TestHelloWorld類不變,運行結果以下 :
2017-11-20 00:23:05 [org.springframework.context.annotation.AnnotationConfigApplicationContext]-[INFO] Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@12bb4df8: startup date [Mon Nov 20 00:23:05 CST 2017]; root of context hierarchy 接下去調用Hello()...... Hello:How are you ? 函數Hello()執行結束......
在軟件開發中,散佈於應用中多處的功能被稱爲橫切關注點,一般來說,這些橫切關注點從概念上是與應用的業務邏輯相分離的。把這些橫切關注點和業務邏輯分離出來正是AOP要解決的問題。AOP可以幫咱們模塊化橫切關注點,換言之,橫切關注點能夠被描述爲影響應用多出的功能。這些橫切點被模塊化特殊的類,這些類被稱爲切面。
通知:切面有必需要完成的工做,在AOP中,切面的工做被稱爲通知。通知定義了切面是什麼以及什麼時候使用,除了描述切面要完成的工做,通知還解決了什麼時候執行這個工做的問題,它應該在某個方法以前?以後?以前和以後都調用?仍是隻在方法拋出異常時調用?
鏈接點:鏈接點是應用程序執行過程當中,可以插入切面的一個點。
切點:是在鏈接點的基礎上定義切點,比方說一個類由十幾個方法,每一個方法的調用前和調用後均可以插入通知,可是你只想選擇幾個方法插入通知,所以你定義一個切點來選擇你想插入的通知的方法。
切面:切面就是通知和切點的結合。
織入:織入是把切面應用到目標對象並建立新的代理對象的過程,切面在指定的鏈接點被織入到目標對象中。在目標對象的生命週期裏有多個點能夠進行織入:編譯期、類加載期、運行期。其中編譯器織入須要特殊的編譯器,類加載器織入須要特殊的類加載器,spring的AOP 是在運行期織入通知的。
spring提供了AOP的四種支持,分別是:基於代理的經典Spring AOP模式;純POJO切面;@AspectJ註解驅動的切面;@注入式AspectJ切面。spring所建立的通知都是用標準的Java類編寫的,並且定義通知所應用的切點一般會使用註解或在Spring配置文件裏採用XML來編寫。
spring只支持方法級別的鏈接點。
在spring AOP中,要使用AspectJ的切點表達式語言來定義切點,關於Spring AOP的AspectJ切點,最重要的一點就是Spring僅支持AspectJ切點指示器的一個子集:
1.arg() 限制鏈接點匹配參數爲指定類型的執行方法;
2.@args() 限制鏈接點匹配參數由指定註解標註的執行方法;
3.execution() 用於匹配是鏈接點的執行方法;
4.this() 限制鏈接點匹配AOP代理的bean引用爲指定類型的類
5.target 限制鏈接點匹配目標對象爲指定類型的類
6.@target() 限制鏈接點匹配特定的執行對象,這些對象對應的類要具備指定類型的註解
7.within() 限制鏈接點匹配指定的類型
8.@within() 限制鏈接點匹配特定註解所標註的類型
9.@annotation 限定匹配帶有指定註解的鏈接點
目標對象:
package concert; public interface Performance{ public void perform(); }
切面對象:
package concert; @Aspect//表示Audience的實例是一個切面 public class Audience{ @Before("execution(**concert.Performance.perform(..))") public void silenceCellPhones(){ //在perfrom方法執行以前 } @Before("execution(**concert.Performance.perform(..))") public void takeSeats(){ //在perfrom方法執行以前 } @AfterReturning("execution(**concert.Performance.perform(..))") public void silenceCellPhones(){ //在perfrom方法執行以後 } @AfterThrowing("execution(**concert.Performance.perform(..))") public void silenceCellPhones(){ //在perfrom方法拋出異常以後 } }
上面的類中切點表達式execution(**concert.Performance.perform(..))屢次出現,咱們也能夠經過@Pointcut註解避免每次都寫很長的切點表可是以下所示:
@Aspect//表示Audience的實例是一個切面 public class Audience{ @Pointcut("execution(**concert.Performance.perform(..))") public void performance(){} @Before("performance()") public void silenceCellPhones(){ //在perfrom方法執行以前 } @Before("performance()") public void takeSeats(){ //在perfrom方法執行以前 } @AfterReturning("performance()") public void silenceCellPhones(){ //在perfrom方法執行以後 } @AfterThrowing("performance()") public void silenceCellPhones(){ //在perfrom方法拋出異常以後 } }
接下來須要在配置文件中配置切面以下所示:
@Configuration @EnableAspectJAutoProxy//啓動AspectJ自動代理 @ComponentScan public class ConcertConfig{ } //或者在配置文件中配置中添加 <aop:aspectj-autoproxy /> 表示啓動切面代理
環繞通知:
@Aspect//表示Audience的實例是一個切面 public class Audience{ @Pointcut("execution(**concert.Performance.perform(..))") public void performance(){} @Before("performance()") public void watchPerformance(ProceedingJoinPoint jp){ //在方法以前執行 System.out.println(" beform the method is invoked"); jp.proceed()//控制權交給目標方法 //在方法以後執行 System.out.println(" after the method is invoked"); } }
public class Audience{ @Pointcut("execution(**concert.Performance.perform(int))&&args(trackNumber)") public void performance(){} @Before("performance(trackNumber)") public void watchPerformance(int trackNumber){ //截獲傳遞給目標方法的參數並傳遞給切面中處理方法 System.out.println(trackNumber); } }
spring AOP提供的xml配置元素:
1.<aop:advisor> 定義AOP通知;
2.<aop:after> 後置通知;
3.<aop:after-returning> 返回通知
4.<aop:around> 環繞通知
5.<aop:aspect> 定義一個切面
6.<aop:aspectj-autoproxy> 啓用切面註解驅動
7.<aop:before> 前置通知
8.<aop:config> 頂層的AOP配置元素;
9.<aop:pointcut>:定義個切點
<aop:config> <aop:aspect ref="audience"> <aop:before pointcut="execution(**concert.Performance.perform())" method="silenceCellPhones"/> <aop:before pointcut="execution(**concert.Performance.perform())" method="takeSeats"/> <aop:after-returning pointcut="execution(**concert.Performance.perform())" method="applause"/> <aop:after-throwing pointcut="execution(**concert.Performance.perform())" method="demandRefund"/> </aop:aspect> </aop config>
定義切點:
<aop:config> <aop:aspect ref="audience"> <aop:pointcut id="performance" expression="execution(**concert.Performance.perform())"> <aop:before pointcut-ref="performance" method="silenceCellPhones"/> <aop:before pointcut="performance" method="takeSeats"/> <aop:after-returning pointcut="performance" method="applause"/> <aop:after-throwing pointcut="performance" method="demandRefund"/> </aop:aspect> </aop config>