AOP:面向切面编程
正常程序执行顺序都是纵向执行流程。AOP是在原有纵向执行过程之中添加一个横切面,不需要修改原有程序代码(体现出程序高扩展性)。
原有功能相当于释放部分逻辑。
面向切面编程:在程序原有纵向执行流程中,针对某一个或者某一些方法添加通知形成横切面的过程。
常用概念:
原有功能:切点,pointCut
前置通知:在切点之前执行的方法或者功能,before advice
后置通知:在切点之后执行的方法或者功能,after advice
如果切点执行过程中出现异常,将触发异常通知,throws advice
所有功能总称为切面
织入:将切面嵌入到原有功能的过程
Spring提供两种AOP实现方式:
1.Schema-based(每个通知都需要实现接口或类),在spring配置文件内,在<aop:config>配置
实现步骤:
(1)导入jar(spring基础包+aopalliance+aspectweaver+commons-logging+spring-aop+spring-aspect+spring-tx)
(2)新建通知类
(3)配置spring配置文件
引入aop命名空间
配置通知类的<bean>
配置切面
编写测试代码
运行结果
表示通配符,可以匹配任意方法名,任意类名,任意一级包名
如果希望匹配任意方法参数,使用(..),如 com..(..)
appllicationContext.xml:
<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"
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">
<bean id="demo" class="com.Demo"/>
<bean id="mybefore" class="com.advice.MyBeforeAdvice"/>
<bean id="myafter" class="com.advice.MyAfterAdvice"/>
<aop:config>
<aop:pointcut id="mypoint" expression="execution(* com.Demo.demo2())"></aop:pointcut>
<aop:advisor advice-ref="mybefore" pointcut-ref="mypoint"/>
<aop:advisor advice-ref="myafter" pointcut-ref="mypoint"/>
</aop:config>
</beans>
MyAfterAdvice:
package com.advice;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class MyAfterAdvice implements AfterReturningAdvice {
@Override
public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
System.out.println("方法返回值:" + o);
System.out.println("方法对象:" + method.getName());
System.out.println("方法参数:" + objects);
System.out.println("方法所在对象:" + o1);
System.out.println("执行后置通知");
}
}
MyBeforeAdvice:
package com.advice;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class MyBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("方法对象:" + method.getName());
System.out.println("方法参数:" + objects);
System.out.println("方法所在对象:" + o);
System.out.println("执行前置通知");
}
}
Demo:
package com;
public class Demo {
public void demo1() {
System.out.println("demo1");
}
public void demo2() {
System.out.println("demo2");
}
public void demo3() {
System.out.println("demo3");
}
}
Test:
package com;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
Demo demo = ac.getBean("demo", Demo.class);
demo.demo2();
}
}
环绕通知:(前置通知与后置通知写在一个方法中)
package com.advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class MyArround implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
System.out.println(1);
Object result = methodInvocation.proceed();
System.out.println(2);
return result;
}
}
<bean id="demo" class="com.Demo"/>
<bean id="myArround" class="com.advice.MyArround"></bean>
<aop:config>
<aop:pointcut id="mypoint" expression="execution(* com.Demo.demo1())"/>
<aop:advisor advice-ref="myArround" pointcut-ref="mypoint"/>
</aop:config>
2.AspectJ(每个通知不需要实现接口),配置spring配置文件时<aop:config>的子标签<aop:aspect>中配置
当切点报异常时才能够触发异常通知
AspectJ方式提供异常通知方法
<bean id="demo" class="com.Demo"/>
<bean id="myThrow" class="com.advice.MyExceptionAdvice"></bean>
<aop:config>
<aop:aspect ref="myThrow">
<aop:pointcut id="mypoint" expression="execution(* com.Demo.demo2())"/>
<aop:after-throwing method="exceptionThrow" pointcut-ref="mypoint" throwing="ex"/>
</aop:aspect>
</aop:config>
package com;
public class Demo {
public void demo1() {
System.out.println("demo1");
}
public void demo2() throws Exception {
int i = 1 / 0;
System.out.println("demo2");
}
public void demo3() {
System.out.println("demo3");
}
}
package com;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
Demo demo = ac.getBean("demo", Demo.class);
try {
demo.demo2();
} catch (Exception e) {
}
}
}
注:<aop:after>与<aop:after-returning>当切点正常执行时,执行先后顺序根据标签顺序决定,但是当有异常时,after-returning将不执行。
环绕通知遇到异常时只执行前置通知。
且AsprctJ方式的环绕通知方法需要加参数ProceedingJointPoint
网友评论