1. 程式人生 > >@AspectJ註解驅動,基於xml檔案的配置方式

@AspectJ註解驅動,基於xml檔案的配置方式

基於xml檔案的配置方式,使用@AspectJ註解驅動.需要引入額外的jar包,即aspectj,從官網下載即可.

aop:scoped-proxy 代理的作用域
aop:aspectj-autoproxy 開啟@AspectJ註解驅動
aop:config 定義一個spring aop
aop:advisor 定義一個通知器
aop:aspect 定義一個切面
aop:before
定義前置通知
aop:after 定義後置通知
aop:around 定義環繞通知
aop:after-returning 定義返回通知
aop:after-throwing 定義異常通知
aop:declare-parents 對目標物件引入新特性
aop:pointcut 定義一個可複用的切點

目標物件的介面和類

package siye;
public interface User
{
	void work();// 使用者工作
}
package siye;

public class UserImpl implements User {

	@Override
	public void work() {
		System.out.println("user_work");
	}

	public int getSalary() {
		return 0;
	}

	public void goHome() {
		System.out.println("user_go_home");
	}

	public void throwOwn() {
		throw new RuntimeException();
	}

}

對目標物件新增特性的介面和類

package siye;
public interface Animal
{
	void eat();
}
package siye;
public class AnimalImpl implements Animal
{
	@Override
	public void eat()
	{
		System.out.println("animal_eat_food");
	}
}

定義的切面類

package siye;
import org.aspectj.lang.ProceedingJoinPoint;
public class CustomAspect
{
	public void before()
	{
		System.out.println("方法即將執行----advice_before");
	}
	public void after()
	{
		System.out.println("方法執行完畢----advice_after");
	}
	public void afterReturning()
	{
		System.out.println("方法正常返回---advice_afterReturning");
	}
	public void aroundMethod(ProceedingJoinPoint jp)
	{
		try
		{
			System.out.println("user_start_back_home");
			jp.proceed();
			System.out.println("user_back_home");
		} catch (Throwable e)
		{
		}
	}
	public void throwException()
	{
		System.out.println("方法丟擲異常----advice_throwException");
	}
}

xml配置檔案設定,檔名`config.xml`

<bean id="userImpl" class="siye.UserImpl" />                                    
<bean id="aspect" class="siye.CustomAspect" />                                  
                                                                                
                                                                                
<!--強制使用cglib代理. -->                                                            
<aop:config proxy-target-class="true">                                          
	<aop:aspect ref="aspect">                                                   
		<!--定義切點. -->                                                           
		<aop:pointcut                                                           
			expression="execution(* *.UserImpl.work(..))" id="funWork" />       
		<!--前置通知. -->                                                           
		<aop:before method="before" pointcut-ref="funWork" />                   
		<!--後置通知. -->                                                           
		<aop:after method="after" pointcut-ref="funWork" />                     
		<!--環繞通知. -->                                                           
		<aop:after-returning method="afterReturning"                            
			pointcut="execution(* *.getSalary(..))" />                          
		<!--返回通知. -->                                                           
		<aop:around method="aroundMethod"                                       
			pointcut="execution(* *.goHome(..))" />                             
		<!--異常通知. -->                                                           
		<aop:after-throwing method="throwException"                             
			pointcut="execution(* *.throwOwn(..))" />                           
		<!--introduction_by_xml -->                                             
		<aop:declare-parents types-matching="siye.User+"                        
			implement-interface="siye.Animal" default-impl="siye.AnimalImpl" /> 
	</aop:aspect>                                                               
</aop:config>                                                                   

測試類

package siye;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class UintTest
{
	public static void main(String[] args)
	{
		ClassPathXmlApplicationContext context =
				new ClassPathXmlApplicationContext();
		context.setConfigLocation("classpath:/siye/config.xml");
		context.refresh();
		/*
		 * 以下三種獲取bean的方式,都會報錯異常.
		 * 因spring aop配置的不是強制使用cglib動態代理.
		 * 
		 * 設定屬性proxy-target-class="true"
		 * 這將強制spring aop使用cglib動態代理.
		 * 
		 * 註解S2,EnableAspectJAutoProxy中,設定
		 * boolean proxyTargetClass() default false;
		 * 此屬性為true即可.
		 */
		// NoSuchBeanDefinitionException: No qualifying bean of type
		// 'std_aop_byxml.UserImpl' available
		// UserImpl userImpl = context.getBean(UserImpl.class);

		// BeanNotOfRequiredTypeException: Bean named 'userImpl' is expected to be of
		// type 'std_aop_byxml.UserImpl' but was actually of type
		// 'com.sun.proxy.$Proxy2'
		// UserImpl userImpl = context.getBean("userImpl", UserImpl.class);

		// ClassCastException: com.sun.proxy.$Proxy2 cannot be cast to
		// std_aop_byxml.UserImpl
		// UserImpl userImpl = (UserImpl) context.getBean("userImpl");
		// userImpl.work();

		UserImpl userImpl = context.getBean(UserImpl.class);
		// userImpl.work(); // 測試前置和後置通知.
		// userImpl.getSalary();// 測試返回通知
		// userImpl.goHome();// 測試環繞通知.
		// userImpl.throwOwn();// 測試異常通知.
		/*
		 * 為目標介面的子類,引入新的特性.
		 */
		Animal animal = (Animal) userImpl;
		animal.eat();
		context.close();
	}
}