springAOP之aspectJ(一)

一:目標類 Seller.java

package aopAspectj;

public class Seller {
	public void sellerBefore(){
		System.out.println("in seller sellerBefore run");
	}
	public void sellerBeforeParam(String name){
		System.out.println("in seller sellerBeforeParma run--->"+name);
	}
	public void sellerCommonMethod(String name){
		System.out.println("in seller commonMethod run--->"+name);
	}
	
	public void sellerAfter(){
		System.out.println("in seller sellerAfter run");
	}
	public void sellerAfterThrowing() throws Exception{
		System.out.println("in seller sellerAfterThrowing run");
		throw new Exception("exception");
	}
	public String sellerAfterReturn(String name){
		System.out.println("in seller sellerReturn run--->"+name);
		return name;
	}
	public void sellerAround(){
		System.out.println("in seller sellerAround run");
	}
}

二:切面類(增強)

package aopAspectj;

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.hibernate.annotations.Target;
import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor;

/**
 * 通過註解定義一個切面。 通過@Aspect註解定義advisor時,沒有繼承任何類和實現任何接口,我們在
 * advisor包中配置的兩個切面都實現了接口,只不過regexp切面 本身的
 * 功能已經很完善,沒有對齊進行擴展,而StaticMethodMatcherPointcutAdvisor切面我們定義了一個擴展類
 * 
 * 所有的增強方法都可以加入入參 JointPoint 用以獲得鏈接點信息,around增強比較特殊,是ProceedingJoinPoint
 * @author majian
 * 
 */
@Aspect
public class AspectjAdvisor {

	/**
	 * "*" 代表單個元素,(一個單詞,或一個字母,".." 表示任意個元素) 任意公共方法的執行: execution(public * *(..))
	 * 任何一個名字以“set”開始的方法的執行: execution(* set*(..)) AccountService接口定義的任意方法的執行:
	 * execution(* com.xyz.service.AccountService.*(..)) 在service包中定義的任意方法的執行:
	 * execution(* com.xyz.service.*.*(..)) 在service包或其子包中定義的任意方法的執行:
	 * execution(* com.xyz.service..*.*(..))
	 * */
	/**###################################################*/
	
	/**before 不帶參數的前置增強*/
	@Before(value="execution(* sellerBefore(..))")
	public void beforeAdvisor(){
		System.out.println("in advisor beforeAdvisor");
	}
	/** before 帶參數的前置增強,參數要與目標類中要調用的方法名相同,多個參數用逗號隔開*/
	@Before(value = "execution(* sellerBeforeParam(..)) && args(name)", argNames = "name")
	public void beforeAdvisorParam(String name) {
		System.out.println("in advisor beforeAdvisorParam--->" + name);
	}

	/**
	 * 在每一個advice方法中都配置切點表達式過於麻煩,可以標註一個公共的切點函數,
	 * 用以描述切點信息,沒有返回值,只做標註使用,其他的標註了@befor,@afterreturning等的方法 就可以在value屬性中直接調用了
	 * */
	@Pointcut(value = "execution(* sellerCommonMethod(..)) && args(name)", argNames = "name")
	public void markMethod(String name) {
	}

	/** 調用上面統一的切點表達式 */
	@Before(value = "markMethod(name)", argNames = "name")
	public void commonMethod(String name) {
		System.out.println("in advisor commonMethod--->" + name);
	}
	
	/**after增強*/
	@After(value="execution(* sellerAfter(..))")
	public void afterAdvisor(){
		System.out.println("in advisor afterAdvisor");
	}
	
	/**afterThrowing 拋出異常增強*/
	@AfterThrowing(value="execution(* sellerAfterThrowing(..))",throwing="exception")
	public void afterThrowingAdvisor(Exception exception ){
		System.out.println("in advisor afterThrowingAdvisor--->"+exception);
	}
	
	/** #################################################################### **/
	/**
	 * 後置返回增強
	 * 
	 * @AfterReturning( value="切入點表達式或命名切入點", 
	 * 					pointcut="和value同義,會覆蓋value",
	 *                  argNames="參數列表參數名", 
	 *                  returning="目標方法的返回值")
	 * 
	 * */
	@AfterReturning(value="execution(* sellerAfterReturn(..))",
			argNames="name",returning="name")//目標方法加一個入參會怎樣?
	public void afterReturn(String name) {
		System.out.println("in advisor afterReturn--->"+name);
	}
	
	/**around 增強,這個比較特殊,
	 * @throws Throwable */
	@Around(value="execution(* sellerAround(..))")
	public Object aroundAdvisor(ProceedingJoinPoint pjp) throws Throwable{
		System.out.println("in advisor aroundAdvisor before");
		    Object retVal = pjp.proceed(new Object[] {});  
		    System.out.println("in advisor aroundAdvisor end");
		    return retVal; 
		
	}
}

三:IOC容器配置文件(這裏配置了倆個,爲了把不同的功能分開,看的更清楚)也可以用註解的方式

applicationContext1.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:jaxws="http://cxf.apache.org/jaxws"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                        http://www.springframework.org/schema/context
                        http://www.springframework.org/schema/context/spring-context-3.0.xsd
                        http://cxf.apache.org/jaxws
                        http://cxf.apache.org/schemas/jaxws.xsd
                        http://www.springframework.org/schema/tx
                        http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
    <context:component-scan base-package="dao,model,service,client,advice" />
<!--目標bean  -->
<bean id="seller" class="aopAspectj.Seller"></bean>
<!--使用了aspectj註解的切面類  -->
<bean class="aopAspectj.AspectjAdvisor"></bean>
<!--自動代理創建器,自動將標註了 @aspectj註解的切面類 植入目標bean中-->
<!--引入了aop命名空間的話可以用    <aop:aspectj-autoproxy />代替  -->
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"></bean>
</beans>

applicationContext2.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:jaxws="http://cxf.apache.org/jaxws"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/aop    
          				http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
   						http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                        http://www.springframework.org/schema/context
                        http://www.springframework.org/schema/context/spring-context-3.0.xsd
                        http://cxf.apache.org/jaxws
                        http://cxf.apache.org/schemas/jaxws.xsd
                        http://www.springframework.org/schema/tx
                        http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
    <context:component-scan base-package="dao,model,service,client,advice" />
<!--基於aop的aspectj的配置方式 .下面aop標籤有個 proxy-target-class爲false表示使用jdk的動態代理進行 植入增強-->
<aop:aspectj-autoproxy proxy-target-class="true" />
<!--目標bean  -->
<bean id="seller" class="aopAspectj.Seller"></bean>
<!--使用了aspectj註解的切面類  -->
<bean class="aopAspectj.AspectjAdvisor"></bean>

</beans>

三:測試類

package aopAspectj;

import static org.junit.Assert.*;

import org.junit.Test;
import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AspectjTest {
	/**before 代碼的方式生成目標類的代理*/
	@Test
	public void test1() {
		Seller Seller = new Seller();
		// aspectj工廠
		AspectJProxyFactory factory = new AspectJProxyFactory();
		// 設置目標對象
		factory.setTarget(Seller);
		// 添加切面類 此處的切面類AspectjAdvisor必須是標註了@aspectj註解的切面類
		factory.addAspect(AspectjAdvisor.class);
		// 生成植入切面的代理對象
		Seller proxy = factory.getProxy();
		proxy.sellerBeforeParam("zhangsan");
	}
	
	/**before 配置文件的方式*/
	@Test
	public void test2() {
		ApplicationContext context=new ClassPathXmlApplicationContext("aopAspectj/applicationContext1.xml");
		Seller Seller=(Seller)context.getBean("seller");
		Seller.sellerBeforeParam("zhangsan");
	}
	
	/**before 使用aop命名空間的配置(就是不用配置自動代理bean了,以一個aop元素代替了)*/
	@Test
	public void test3(){
		ApplicationContext context=new ClassPathXmlApplicationContext("aopAspectj/applicationContext2.xml");
		Seller seller=(Seller)context.getBean("seller");
		seller.sellerBeforeParam("zhangsan");
		
	}
	/**before 不在@before(value="")中配置切點,而是把切點配置在一個公共的標記方法中,其他標註了@before,@around
	 *的切點註解中,再value屬性中直接調用這個方法
	 * */
	@Test
	public void test4(){
		ApplicationContext context=new ClassPathXmlApplicationContext("aopAspectj/applicationContext2.xml");
		Seller seller=(Seller)context.getBean("seller");
		seller.sellerCommonMethod("zhangsan");
	}
	/**before 不帶參數 advice增強*/
	@Test
	public void test5(){
		ApplicationContext context=new ClassPathXmlApplicationContext("aopAspectj/applicationContext2.xml");
		Seller seller=(Seller)context.getBean("seller");
		seller.sellerBefore();
	}
	/**before 帶參數的advice增強*/
	@Test
	public void test6(){
		ApplicationContext context=new ClassPathXmlApplicationContext("aopAspectj/applicationContext2.xml");
		Seller seller=(Seller)context.getBean("seller");
		seller.sellerBeforeParam("zhangsan");
	}
	
	/**after增強*/
	@Test
	public void test7(){
		ApplicationContext context=new ClassPathXmlApplicationContext("aopAspectj/applicationContext2.xml");
		Seller seller=(Seller)context.getBean("seller");
		seller.sellerAfter();
	}
	/**afterThrowing增強
	 * @throws Exception */
	@Test
	public void test8() throws Exception{
		ApplicationContext context=new ClassPathXmlApplicationContext("aopAspectj/applicationContext2.xml");
		Seller seller=(Seller)context.getBean("seller");
		seller.sellerAfterThrowing();
	}
	
	/**afterReturn 增強*/
	@Test
	public void test9(){
		ApplicationContext context=new ClassPathXmlApplicationContext("aopAspectj/applicationContext2.xml");
		Seller seller=(Seller)context.getBean("seller");
		seller.sellerAfterReturn("lisi");
	}
	
	/**around 增強*/
	@Test
	public void test10(){
		ApplicationContext context=new ClassPathXmlApplicationContext("aopAspectj/applicationContext2.xml");
		Seller seller=(Seller)context.getBean("seller");
		seller.sellerAround();
	}
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章