AspectJ 基於xml開發和基於註解的開發

AspectJ

1、概念

AspectJ是一個基於Java語言的AOP框架。Spring2.0以後新增了對AspectJ切點表達式支持。@AspectJ 是AspectJ1.5新增功能,通過JDK5註解技術,允許直接在Bean類中定義切面。新版本Spring框架,建議使用AspectJ方式來開發AOP。主要用途:自定義開發。

2、切入點表達式

表達式execution(*com.Lily.spring_aop.*.*(..))

      語法:execution(修飾符  返回值  包.類.方法名(參數) throws異常)

      修飾符【一般省略】:public  *(任意)

      返回值【不能省略】:void  String *(任意)

     

            1、固定包com.Lily. aop

            2、aop包下的所有包,包括自己,包括孫包 com.Lily.aop..

            3、aop包下任意子包,固定目錄Service,Service目錄任意包 com.Lily.aop.*.Service..

      【一般省略】

            1、UserServiceImpl             指定類

            2、 *Impl                           以Impl結尾

            3、 User*                           以User開頭

            4、 *                                 任意

      方法名【不能省略】

            1、addUser                        固定方法

            2、 add*                                  以add開頭

            3、 *Do                             以Do結尾

            4、 *                                  任意

      參數

            1、 ()                                 無參

            2、 (int)                             一個整型

            3、 (int ,int)                        兩個

            4、 (..)                               參數任意

異常【可省略,一般不寫】

3、AspectJ通知類型

AOP聯盟定義了6種通知類型,具有特性接口,必須實現對應的接口,從而確定方法名稱。

1.      before:前置通知(應用:各種校驗):在方法執行前執行,如果通知拋出異常,阻止方法運行。

2.      afterReturning:後置通知(應用:常規數據處理):方法正常返回後執行,如果方法中拋出異常,通知無法執行。必須在方法執行後才執行,所以可以獲得方法的返回值。

3.      around:環繞通知(應用:十分強大,可以做任何事情):方法執行前後分別執行,可以阻止方法的執行。  必須手動執行目標方法

4.      afterThrowing:拋出異常通知(應用:包裝異常信息):方法拋出異常後執行,如果方法沒有拋出異常,無法執行。

5.      after:最終通知(應用:清理現場):方法執行完畢後執行,無論方法中是否出現異常。

4、基於xml的aop編程

1、導入Jar包

【前面AOP的包和Spring的4+1包都是默認導入】

spring-aspects-3.2.0.RELEASE.jar

2、編寫UserService接口

public interface UserService {
	public void addUser();
	public String updateUser();
	public void deleteUser();
}


3、編寫接口的實現類

public class UserSerImpl implements UserService {

	/* (non-Javadoc)
	 * @see com.Lily.SpringLearning.h_AspectJ.UserService#addUser()
	 */
	@Override
	public void addUser() {
		// TODO Auto-generated method stub
System.out.println("AspectJ  add() "+this.getClass().getName());
	}

	/* (non-Javadoc)
	 * @see com.Lily.SpringLearning.h_AspectJ.UserService#updateUser()
	 */
	@Override
	public String updateUser() {
		// TODO Auto-generated method stub
		System.out.println("AspectJ  update() "+this.getClass().getName());
		//引入Exeception
		int i=1/0;
		
		return "See my Error?";
	}

	/* (non-Javadoc)
	 * @see com.Lily.SpringLearning.h_AspectJ.UserService#deleteUser()
	 */
	@Override
	public void deleteUser() {
		// TODO Auto-generated method stub
		System.out.println("ASpectJ  delete()  ");
	}

}


4、切面類

這裏將上述的5中通知類型都寫入了,需要哪種就用哪種。【一般要求掌握的是環繞通知,因爲有前有後,但是還是要根據實際的需求來定】

public class LilyAspcet {
	
	public void LilyBefore(JoinPoint jp){
		System.out.println("前置通知:  "+jp.getSignature().getName());		
	}
	
	public void LilyAfterReturning(JoinPoint jp,Object obj){
		System.out.println("後置通知:  "+jp.getSignature().getName()+" → "+obj);		
	}	
	
	
	public Object LilyAround(ProceedingJoinPoint jp)throws Throwable{
		System.out.println("around的前方法");
		//手動執行目標方法
		Object obj=jp.proceed();
		System.out.println("around的後方法");
		return obj;
		
	}
	
	public void LilyAfterThrowing(JoinPoint jp,Throwable e){
		System.out.println("拋出異常通知 "+e.getMessage());
	}
	
	public void LilyAfter(JoinPoint jp){
		System.out.println("一定會出現的 最 終  通  知 ~");
	}
	

}


5、編寫bean.xml

【這裏要注意,不能同時使用多個通知類型,使用哪個就寫哪個,舉例是前置通知,其他的通知就將<aop:??method="" pointcut-ref="myPointCut"/>的方法名改成對應的方法名即可】

前置通知 <aop:before method="LilyBefore" pointcut-ref="myPointCut"/>

後置通知 <aop:after-returning method="LilyAfterReturning"pointcut-ref="myPointCut" returning="obj"/>

環繞通知 <aop:around method="LilyAround"pointcut-ref="myPointCut"/>

拋出異常 <aop:after-throwing method="LilyAfterThrowing" pointcut-ref="myPointCut"throwing="e"/>

最終通知  <aop:after method="LilyAfter"pointcut-ref="myPointCut"/>

<?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"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
       					   http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
       					   http://www.springframework.org/schema/aop 
       					   http://www.springframework.org/schema/aop/spring-aop.xsd">
	
	
	
	<bean id="userServiceId" class="com.Lily.SpringLearning.h_AspectJ.UserSerImpl"></bean>
	
	<bean id="LilyAspect" class="com.Lily.SpringLearning.h_AspectJ.LilyAspcet"></bean>
	
	<aop:config>
		<aop:aspect ref="LilyAspect">
			<aop:pointcut expression="execution(* com.Lily.SpringLearning.h_AspectJ.UserSerImpl.*(..))" id="myPointCut"/>
			<!--aop:before method="LilyBefore" pointcut-ref="myPointCut"/>-->
			<!--aop:after-returning method="LilyAfterReturning" pointcut-ref="myPointCut" returning="obj"/>-->
			<!--aop:around method="LilyAround" pointcut-ref="myPointCut"/>-->
			<aop:after-throwing method="LilyAfterThrowing" pointcut-ref="myPointCut" throwing="e"/>
			<!--aop:after method="LilyAfter" pointcut-ref="myPointCut"/>  -->
			
		
		</aop:aspect>	
	</aop:config>	
	
</beans>


6、編寫測試類

 

public class TestAspectJ {

	@Test
	public void test() {
		String xmlPath = "com/Lily/SpringLearning/h_AspectJ/beans.xml";
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
		
		//獲得目標類
		UserService userService = (UserService) applicationContext.getBean("userServiceId");
		userService.addUser();
		userService.updateUser();
		userService.deleteUser();
	}

}

5、基於註解的aop編程

1、需要在實現類上添加註解 @Service("userServiceId")

@Service("userServiceId")
public class UserSerImpl implements UserService {

	/* (non-Javadoc)
	 * @see com.Lily.SpringLearning.h_AspectJ.UserService#addUser()
	 */
	@Override
	public void addUser() {
		// TODO Auto-generated method stub
System.out.println("AspectJ  add() "+this.getClass().getName());
	}

	/* (non-Javadoc)
	 * @see com.Lily.SpringLearning.h_AspectJ.UserService#updateUser()
	 */
	@Override
	public String updateUser() {
		// TODO Auto-generated method stub
		System.out.println("AspectJ  update() "+this.getClass().getName());
		//引入Exeception
		int i=1/0;
		
		return "See my Error?";
	}

	/* (non-Javadoc)
	 * @see com.Lily.SpringLearning.h_AspectJ.UserService#deleteUser()
	 */
	@Override
	public void deleteUser() {
		// TODO Auto-generated method stub
		System.out.println("ASpectJ  delete()  ");
	}

}


2、需要修改Aspect類,最頂端添加註解@Component和@Aspect,在對應方法上聲明切入點/前置通知/環繞通知/後置通知/拋出異常/最終通知。【注意,拋出異常的通知要寫Throwable e,後置通知要註明returning="obj"】

@Component
@Aspect
public class LilyAspcet {
	
	//聲明公共切入點,方便後續引用。若不聲明,則每個通知需寫自己的切入點表達式。
	@Pointcut("execution(* com.Lily.SpringLearning.h_AspectJ_anno.UserSerImpl.*(..))")
	private void myPonitCut(){}
	
	//@Before("execution(* com.Lily.SpringLearning.h_AspectJ_anno.UserSerImpl.*(..))")
	//@Before(value="myPonitCut()")
	public void LilyBefore(JoinPoint jp){
		System.out.println("前置通知:  "+jp.getSignature().getName());		
	}
	
//	@AfterReturning(value="myPonitCut()",returning="obj")
	public void LilyAfterReturning(JoinPoint jp,Object obj){
		System.out.println("後置通知:  "+jp.getSignature().getName()+" → "+obj);		
	}	
	
//	@Around (value="myPonitCut()")
	public Object LilyAround(ProceedingJoinPoint jp)throws Throwable{
		System.out.println("around的前方法");
		//手動執行目標方法
		Object obj=jp.proceed();
		System.out.println("around的後方法");
		return obj;
		
	}
	@AfterThrowing(value="myPonitCut()",throwing="e")
	public void LilyAfterThrowing(JoinPoint jp,Throwable e){
		System.out.println("拋出異常通知 "+e.getMessage());
	}
	//@After("myPonitCut()")
	public void LilyAfter(JoinPoint jp){
		System.out.println("一定會出現的 最 終  通  知 ~");
	}
	

}



3、在xml配置文件中,掃描註解類、並確定aop註解生效。

 

<?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.xsd
       					   http://www.springframework.org/schema/aop 
       					   http://www.springframework.org/schema/aop/spring-aop.xsd
       					   http://www.springframework.org/schema/context 
       					   http://www.springframework.org/schema/context/spring-context.xsd">
	
	
	
	<context:component-scan base-package="com.Lily.SpringLearning.h_AspectJ_anno"></context:component-scan>
	

<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

</beans>


註解第一次報錯

org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException:Line 13 in XML document from class path resource[com/Lily/SpringLearning/h_AspectJ_anno/beans.xml] is invalid; nested exceptionis org.xml.sax.SAXParseException; lineNumber: 13; columnNumber: 80;cvc-complex-type.2.4.c: 通配符的匹配很全面, 但無法找到元素 'context:component-scan' 的聲明。

      atorg.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:396)

      atorg.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:334)

      atorg.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:302)

      atorg.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:174)

      atorg.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:209)

      atorg.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:180)

      atorg.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:243)

      atorg.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:127)

      atorg.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:93)

      atorg.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:131)

      atorg.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:537)

      atorg.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:451)

      atorg.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)

      atorg.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)

      atcom.Lily.SpringLearning.h_AspectJ_anno.TestAspectJ.test(TestAspectJ.java:26)

      atsun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

      atsun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)

      atsun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

      atjava.lang.reflect.Method.invoke(Method.java:606)

      atorg.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)

      atorg.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)

      atorg.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)

      atorg.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)

      atorg.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)

      atorg.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)

      atorg.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)

      atorg.junit.runners.ParentRunner$3.run(ParentRunner.java:238)

      atorg.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)

      atorg.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)

      atorg.junit.runners.ParentRunner.access$000(ParentRunner.java:53)

      atorg.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)

      atorg.junit.runners.ParentRunner.run(ParentRunner.java:309)

      atorg.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)

      atorg.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)

      atorg.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)

      atorg.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)

      atorg.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)

      atorg.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

Caused by: org.xml.sax.SAXParseException;lineNumber: 13; columnNumber: 80; cvc-complex-type.2.4.c: 通配符的匹配很全面, 但無法找到元素 'context:component-scan' 的聲明。

      atcom.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:198)

      atcom.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.error(ErrorHandlerWrapper.java:134)

      atcom.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:437)

      atcom.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:368)

      atcom.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:325)

      atcom.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator$XSIErrorReporter.reportError(XMLSchemaValidator.java:458)

      atcom.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.reportSchemaError(XMLSchemaValidator.java:3237)

      atcom.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.handleStartElement(XMLSchemaValidator.java:1917)

      atcom.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.startElement(XMLSchemaValidator.java:746)

      atcom.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanStartElement(XMLNSDocumentScannerImpl.java:378)

      atcom.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:2778)

      atcom.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:606)

      atcom.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:117)

      atcom.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:510)

      atcom.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:848)

      atcom.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:777)

      atcom.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)

      atcom.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:243)

      atcom.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:347)

      atorg.springframework.beans.factory.xml.DefaultDocumentLoader.loadDocument(DefaultDocumentLoader.java:75)

      atorg.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:388)

      ...37 more

 查了一下,xml文件忘記了添加

http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/spring-context.xsd



AOP註解開發總結:

@Aspect 聲明切面,修飾切面類,從而獲得通知。

@PointCut,修飾方法 private void xxx(){},之後通過 方法名 獲得切入點引用。


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