什么是AOP
AOP是面对切面的额编程,通过以便以的方式和运行期动态代理实现程序供的统一维护的技术。
功能:日志记录,性能统计,安全控制,事务处理,异常处理等等。
AOP的实现方式
预编译:Aspectj
运行期动态代理:SpringAOP、JbossAOP。
AOP的基本概念
切面:一个关注点的模块化,这个关注点可能会横切多个对象
连接点:程序执行过程中的某个特定的点
通知:在切面的某个特定的连接点上执行的动作
切入点:匹配连接点的断言,在AOP中通知和一个切入点表达式关联
引入:在不修改类代码的前提下,为类添加新的方法和属性
目标对象:被一个或者多个切面所通知的对象
AOP代理:AOP框架创建的对象,用来实现切面契约
织入:把切面连接到其他的应用程序类型或者对象上,并创建一个被通知的对象,分为:编译时的织入、类加载时织入、执行时织入
Advice通知:
前置通知,返回后通知,抛出异常后通知,退出时通知,环绕通知。
Spring中的AOP
用途:提供声明式的企业服务、允许用户定制自己的方面,以完成OOP和AOP的互补使用。
实现: 纯Java实现,目前只支持方法执行连接点 停供了一种AOP实现和Spring IOC容器之间的整合不会与Aspectj冲突。
Schema-based AOP
所有的切面和通知器都要放在<aop:config>中,可以包含pointcut,advisor,aspect元素。(必须按照顺序声明)
<aop:aspect> id:指定切面的唯一标识符,rel:将该Bean作为一个切面。
<aop:pointcut>id:切入点的唯一标识符,execution:切入点的配置
execution(public * *(..)) 切入点为所有的public方法执行时
execution(* set*(..))切入点为执行所有以set开头的方法时
execution(* xxx.yyy.zzz.aaa.*(..))切入点为执行aaa类中所有的方法时
execution(* xxx.yyy.zzz..(..))切入点为执行zzz包下所有方法时
execution(* xxx.yyy.zzz...(..))切入点为执行zzz包下及其子包的所有方法时
Advice:
before:<aop:before method="before" pointcut-ref="apppointcut"/>
前缀通知,在执行切入点前运行before方法。
after-returning:<aop:after-returning method="before" pointcut-ref="apppointcut"/>
返回之后通知,在切入点返回时运行before方法。
after-throwing:<aop:after-throwing method="before" pointcut-ref="apppointcut"/>
当切入点抛出异常时,运行before方法。
after: <aop:after method="before" pointcut-ref="apppointcut"/>
切入点结束之后,执行before方法
Around:方法的第一个参数必须是ProceedingJoinPoint类型,环绕通知
<aop:around method="before2" pointcut-ref="apppointcut"/>
public Object before2(ProceedingJoinPoint pjp){
Object obj = null;
try {
System.out.println("before2 round1");
obj = pjp.proceed();
System.out.println("before2 round2");
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return obj;
}
使用时一定要导入jar包,不然会报错
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'appAspect' defined in Interface.AppConfig: BeanPostProcessor before instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.aop.aspectj.AspectJPointcutAdvisor#0': Cannot create inner bean '(inner bean)#64cd705f' of type [org.springframework.aop.aspectj.AspectJMethodBeforeAdvice] while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#64cd705f': Failed to introspect bean class [org.springframework.aop.aspectj.AspectJMethodBeforeAdvice] for lookup method metadata: could not find class that it depends on; nested exception is java.lang.NoClassDefFoundError: org/aspectj/lang/JoinPoint
在Maven中添加依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
aop 标签顺序使用错误
org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: Line 11 in XML document from class path resource [spring-config.xml] is invalid; nested exception is org.xml.sax.SAXParseException; lineNumber: 11; columnNumber: 68; cvc-complex-type.2.4.a: 发现了以元素 'aop:before' 开头的无效内容。应以 '{"http://www.springframework.org/schema/aop":pointcut, "http://www.springframework.org/schema/aop":advisor, "http://www.springframework.org/schema/aop":aspect}' 之一开头。
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:399)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:336)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:304)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:181)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:217)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:188)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:252)
at org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:127)
at org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:93)
at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:129)
at org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:614)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:515)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
at Interface.test1.test4(test1.java:25)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: org.xml.sax.SAXParseException; lineNumber: 11; columnNumber: 68; cvc-complex-type.2.4.a: 发现了以元素 'aop:before' 开头的无效内容。应以 '{"http://www.springframework.org/schema/aop":pointcut, "http://www.springframework.org/schema/aop":advisor, "http://www.springframework.org/schema/aop":aspect}' 之一开头。
at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:203)
at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.error(ErrorHandlerWrapper.java:134)
at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:396)
at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:327)
at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:284)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator$XSIErrorReporter.reportError(XMLSchemaValidator.java:453)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.reportSchemaError(XMLSchemaValidator.java:3231)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.handleStartElement(XMLSchemaValidator.java:1791)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.startElement(XMLSchemaValidator.java:741)
at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanStartElement(XMLNSDocumentScannerImpl.java:374)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:2784)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:602)
at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:112)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:505)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:842)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:771)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:243)
at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:339)
at org.springframework.beans.factory.xml.DefaultDocumentLoader.loadDocument(DefaultDocumentLoader.java:76)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadDocument(XmlBeanDefinitionReader.java:429)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:391)
... 36 more
使用aop时,pointcut可以在aspect外,但是before、after-returning、after-throwing、after、around必须在aspect内部。