AOP相关名词
Aspect(切面): Aspect 声明类似于 Java 中的类声明,在 Aspect 中会包含着一些 Pointcut 以及相应的 Advice。
Joint point(连接点):表示在程序中明确定义的点,典型的包括方法调用,对类成员的访问以及异常处理程序块的执行等等,它自身还可以嵌套其它 joint point。
Pointcut(切点):表示一组 joint point,这些 joint point 或是通过逻辑关系组合起来,或是通过通配、正则表达式等方式集中起来,它定义了相应的 Advice 将要发生的地方。
Advice(增强):Advice 定义了在 Pointcut 里面定义的程序点具体要做的操作,它通过 before、after 和 around 来区别是在每个 joint point 之前、之后还是代替执行的代码。
Target(目标对象):织入 Advice 的目标对象.。
schema-base方式增强
前置增强类
package com.demo;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
/*自定义类实现MethodBeforeAdvice接口*/
public class MyBefore implements MethodBeforeAdvice {
/*实现before()方法,方法体为增强内容
* 参数method 切点方法名
* objects 参数集合
* o 切点所在类的对象*/
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("前置通知,执行了");
}
}
后置增强类
package com.demo;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
/*自定义类实现AfterReturningAdvice接口*/
public class MyAfter implements AfterReturningAdvice {
/*实现afterReturning()方法,方法体为增强内容
* o 返回值对象
* 参数method 切点方法名
* objects 参数集合
* o1 切点所在类的对象*/
@Override
public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
System.out.println("后置增强,执行了");
}
}
异常增强
package com.demo;
import org.springframework.aop.ThrowsAdvice;
/*自定义类实现ThrowsAdvice接口*/
public class MyThrow implements ThrowsAdvice {
/*异常通知spring不提供方法,需要自己写。并且名字固定
* 参数 e 异常信息*/
public void afterThrowing(Exception e) throws Throwable{
System.out.println("异常通知,执行了");
}
}
环绕增强
package com.demo;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
/*自定义类实现MethodInterceptor接口*/
public class MyAround implements MethodInterceptor {
/*实现invoke()方法*
参数 methodInvocation 切点方法/
*/
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
/*前置增强先执行*/
System.out.println("环绕前置通知,执行了");
/*通过反射执行切点方法*/
Object obj = methodInvocation.proceed();
/*执行后置增强*/
System.out.println("环绕后置通知,执行了");
return obj;
}
}
配置文件
<?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"
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-4.3.xsd">
<!--将Demo类和写好的通知类交给spring管理-->
<bean id="demo" class="com.demo.Demo"></bean>
<bean id="myBefore" class="com.demo.MyBefore"></bean>
<bean id="myAfter" class="com.demo.MyAfter"></bean>
<bean id="myAround" class="com.demo.MyAround"></bean>
<bean id="myThrow" class="com.demo.MyThrow"></bean>
<!--aop配置-->
<aop:config>
<!--将Demo类的a()方法定义为切点
expression 格式固定 execution(* com.demo.Demo.a()) *为定义通配符
进行模糊匹配可写成execution(* com.demo.*.*(..)) com.demo包下的所有类的所有方法都是切点-->
<aop:pointcut id="mypoint" expression="execution(* com.demo.Demo.a(..))"/>
<!--MyBefore类实现了MethodBeforeAdvice接口,spring就知道他是前置通知-->
<aop:advisor advice-ref="myBefore" pointcut-ref="mypoint"/>
<!--MyAfter类实现了AfterReturningAdvice接口-->
<aop:advisor advice-ref="myAfter" pointcut-ref="mypoint"/>
<!--MyAround类实现了MethodInterceptor接口-->
<aop:advisor advice-ref="myAround" pointcut-ref="mypoint"/>
<!--MyThrow类实现了ThrowsAdvice接口,没有异常不执行-->
<aop:advisor advice-ref="myThrow" pointcut-ref="mypoint"/>
</aop:config>
</beans>
切点类
package com.demo;
import org.springframework.stereotype.Component;
public class Demo {
public String a(int a){
System.out.println("Hello!");
return "hello";
}
}
测试类
package com.test;
import com.demo.Demo;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test1 {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
Demo demo = (Demo) ac.getBean("demo");
demo.a(1);
}
}
运行结果
七月 25, 2019 2:43:50 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@31221be2: startup date [Thu Jul 25 14:43:50 CST 2019]; root of context hierarchy
七月 25, 2019 2:43:50 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [applicationContext.xml]
前置通知,执行了
环绕前置通知,执行了
Hello!
环绕后置通知,执行了
后置增强,执行了
Process finished with exit code 0
AspectJ方式增强
通知类
package com.demo;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/*不需要实现任何接口或继承类*/
public class MyAdvice {
public void before(){
System.out.println("前置增强,执行了");
}
/*发生异常不执行后置增强*/
public void afterReturning(){
System.out.println("后置增强,执行了");
}
/*无论是否发生异常都会执行after*/
public void after(){
System.out.println("最终增强,执行了");
}
public void afterThrow(){
System.out.println("异常增强,执行了");
}
/*不发生异常,环绕前置,后置都执行
* 发生异常只执行前置增强*/
public void around(ProceedingJoinPoint joinPoint) throws Throwable{
/*前置增强先执行*/
System.out.println("环绕前置通知,执行了");
/*通过反射执行切点方法*/
Object obj = joinPoint.proceed();
/*执行后置增强*/
System.out.println("环绕后置通知,执行了");
}
}
配置文件
<?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"
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-4.3.xsd">
<!--将Demo类和写好的通知类交给spring管理-->
<bean id="demo" class="com.demo.Demo"></bean>
<bean id="myAdvice" class="com.demo.MyAdvice"></bean>
<aop:config>
<!--引用myAdvice为增强类
ref 增强类的id-->
<aop:aspect ref="myAdvice">
<!--定义切点-->
<aop:pointcut expression="execution(* com.demo.Demo.a(..))" id="mypoint"/>
<!--前置增强
method 前置增强方法
pointcut-ref 切点的id-->
<aop:before method="before" pointcut-ref="mypoint"/>
<!--后置增强,发生异常不执行-->
<aop:after-returning method="afterReturning" pointcut-ref="mypoint"/>
<!--最终增强,无论是否发生异常都会执行-->
<aop:after method="after" pointcut-ref="mypoint"/>
<!--异常增强,发生异常才会执行-->
<aop:after-throwing method="afterThrow" pointcut-ref="mypoint"/>
<!--环绕增强,前置+后置-->
<aop:around method="around" pointcut-ref="mypoint"/>
</aop:aspect>
</aop:config>
</beans>
不出异常运行结果
七月 25, 2019 3:04:34 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@31221be2: startup date [Thu Jul 25 15:04:34 CST 2019]; root of context hierarchy
七月 25, 2019 3:04:34 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [applicationContext.xml]
前置增强,执行了
环绕前置通知,执行了
Hello!
环绕后置通知,执行了
最终增强,执行了
后置增强,执行了
出异常运行结果
七月 25, 2019 3:05:08 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@31221be2: startup date [Thu Jul 25 15:05:08 CST 2019]; root of context hierarchy
七月 25, 2019 3:05:08 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [applicationContext.xml]
前置增强,执行了
环绕前置通知,执行了
异常增强,执行了
最终增强,执行了
Process finished with exit code 0
使用注解方式
配置文件
<?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.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!--开启spring的扫描,beans中需要加上对应得xsd-->
<context:component-scan base-package="com.demo"></context:component-scan>
<!-- 开启aop注解方式,默认为false -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
切点类
package com.demo;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Component
public class Demo {
public String a(int a) throws Exception{
/*制造异常,向上抛*/
//int i = 1/0;
System.out.println("Hello!");
return "hello";
}
}
增强(切面)类
package com.demo;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/*交给spring管理*/
@Component
/*指定该类为切面类*/
@Aspect
public class MyAdvice {
/*定义切点*/
@Pointcut("execution(* com.demo.Demo.a(..))")
public void pointCut() {
}
@Before("pointCut()")
public void before() {
System.out.println("前置增强,执行了");
}
/*发生异常不执行后置增强*/
@AfterReturning("pointCut()")
public void afterReturning() {
System.out.println("后置增强,执行了");
}
/*无论是否发生异常都会执行after*/
@After("pointCut()")
public void after() {
System.out.println("最终增强,执行了");
}
@AfterThrowing("pointCut()")
public void afterThrow() {
System.out.println("异常增强,执行了");
}
/*不发生异常,环绕前置,后置都执行
* 发生异常只执行前置增强*/
@Around("pointCut()")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
/*前置增强先执行*/
System.out.println("环绕前置通知,执行了");
/*通过反射执行切点方法*/
Object obj = joinPoint.proceed();
/*执行后置增强*/
System.out.println("环绕后置通知,执行了");
}
}
测试类
package com.test;
import com.demo.Demo;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test1 {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
Demo demo = (Demo) ac.getBean("demo");
try {
demo.a(1);
} catch (Exception e) {
}
}
}
无异常运行结果
七月 25, 2019 3:16:14 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@31221be2: startup date [Thu Jul 25 15:16:14 CST 2019]; root of context hierarchy
七月 25, 2019 3:16:14 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [applicationContext.xml]
环绕前置通知,执行了
前置增强,执行了
Hello!
环绕后置通知,执行了
最终增强,执行了
后置增强,执行了
Process finished with exit code 0
有异常运行结果
七月 25, 2019 3:19:44 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@31221be2: startup date [Thu Jul 25 15:19:44 CST 2019]; root of context hierarchy
七月 25, 2019 3:19:45 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [applicationContext.xml]
环绕前置通知,执行了
前置增强,执行了
最终增强,执行了
异常增强,执行了
Process finished with exit code 0