1 解析
1.1 advice中aspect 切面传参
1.2 通知参数名称——argNames属性, 参数为 JoinPoint、ProceedingJoinPoint、JoinPointStaticPart时,可以忽略argNames属性
1.3 其余不重要的部分
2 代码演练
2.1 前置通知@before给advice传递参数
2.1 前置通知@before传递类参数
1 解析
1.1 advice中aspect 切面传参
String传参和类传参参照2.1和2.2
泛型传参
1.2 通知参数名称——argNames属性, 参数为 JoinPoint、ProceedingJoinPoint、JoinPointStaticPart时,可以忽略argNames属性
1.3 其余不重要的部分
Introductions
·允许一个切面声明一个通知对象实现指定接口,并且提供了一个接口实现类来代表这些对象
·introduction使用@DeclareParents进行注解,这个注解用来定义匹配的类型拥有一个新的parent
2 代码演练
2.1 前置通知@before给advice传递String参数
切面类:
package com.imooc.aop.aspectj; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; /** * 注解切面类 * 注:本页面主要功能是:整理各种通知的注解 * @author weijingli * */ @Component @Aspect public class MoocAspect { /** * 该处设置切入点,主要是用来匹配目标对象类 * * 执行com.imooc.aop.aspect.biz 包下的 以Biz结尾的类的所有方法 */ @Pointcut("execution(* com.imooc.aop.aspectj.biz.*Biz.*(..))") public void pointcut(){} /** * 执行com.imooc.aop.aspect.biz 包下的所有类的 所有方法 */ @Pointcut("within(com.imooc.aop.aspectj.biz.*)") public void bizPointcut(){} /** * 前置通知 样例1 */ @Before("execution(* com.imooc.aop.aspectj.biz.*Biz.*(..))") public void before(){ System.out.println("before1"); } /** * AfterReturning 执行后通知,接收 目标对象返回的值 * @param reValue */ @AfterReturning(pointcut="pointcut()",returning="reValue") public void afterReturning(Object reValue){ System.out.println("AfterReturning: "+reValue); } /** * 后置通知 相当于java语法中的finally */ @After("pointcut()") public void after(){ System.out.println("after:"); } /** * 异常通知: * * 接收异常返回的信息 */ @AfterThrowing(pointcut="pointcut()",throwing="e") public void afterThrowing(RuntimeException e){ System.out.println("AfterThrowing: "+e.getMessage()); } /** * 环绕通知: * @param pjp * @return * @throws Throwable */ @Around("pointcut()") public Object around(ProceedingJoinPoint pjp) throws Throwable{ System.out.println("around 1"); Object obj = pjp.proceed(); System.out.println("around 2"); System.out.println("around :"+obj); return obj; } /** * 前置通知 带参数 */ @Before("pointcut()&&args(arg)") public void beforeWithParam(String arg){ System.out.println("beforeWithParam:"+arg); } /** * 前置通知 样例2 */ /*@Before("pointcut()") public void before2(){ System.out.println("before2"); }*/ }
实体类:
package com.imooc.aop.aspectj.biz; import org.springframework.stereotype.Service; @Service public class MoocBiz { /** * 1 为什么 用 save方法 返回 String 类型? * * 答:为了方便After Or AfterReturning 通知 接收 返回值 * * 2 为什么接收String 参数? * * 答:只是为了方便测试,没有任何实际意义。 * @param arg * @return */ public String save(String arg){ System.out.println("MoocBiz save "+arg); // throw new RuntimeException("Save Failed!"); return "Save Success!"; } }
配置文件:
<?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.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd" > <!-- 自己添加注意: 1 context:component-scan 扫描包,根据注解找到通知。 使用注解的时候,记得添加扫描包的功能 2 aop:aspectj-autoproxy 通过配置织入@Aspectj切面 --> <context:component-scan base-package="com.imooc.aop.aspectj"/> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> <bean id="moocBiz" class="com.imooc.aop.aspectj.biz.MoocBiz"></bean> </beans>
测试类:
package com.imooc.test.aop; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.BlockJUnit4ClassRunner; import com.imooc.aop.aspectj.biz.MoocBiz; import com.imooc.test.base.UnitTestBase; /** @RunWith 是一个运行器 * * @RunWith(JUnit4.class)就是指用JUnit4来运行 * *@RunWith(Suite.class)的话就是一套测试集合 * *@RunWith(Suite.class)的话就是一套测试集合 * *@ContextConfiguration Spring整合JUnit4测试时,使用注解引入多个配置文件 * * @author weijingli */ @RunWith(BlockJUnit4ClassRunner.class) public class TestAspectJ extends UnitTestBase{ public TestAspectJ() { super("classpath:spring-aop-aspectj.xml"); } @Test public void testAspectJ(){ MoocBiz mBiz = super.getbean("moocBiz"); mBiz.save("This is Test!"); } }
打印日志:
五月 02, 2019 2:28:44 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh 信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@7fe219e7: startup date [Thu May 02 14:28:44 CST 2019]; root of context hierarchy 五月 02, 2019 2:28:44 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 信息: Loading XML bean definitions from class path resource [spring-aop-aspectj.xml] 五月 02, 2019 2:28:45 下午 org.springframework.beans.factory.support.DefaultListableBeanFactory registerBeanDefinition 信息: Overriding bean definition for bean 'moocBiz' with a different definition: replacing [Generic bean: class [com.imooc.aop.aspectj.biz.MoocBiz]; scope=singleton; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in file [F:\xiangmu3\Xin\FuQiang\Spring\ddwei-dao\target\classes\com\imooc\aop\aspectj\biz\MoocBiz.class]] with [Generic bean: class [com.imooc.aop.aspectj.biz.MoocBiz]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [spring-aop-aspectj.xml]] 五月 02, 2019 2:28:45 下午 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor <init> 信息: JSR-330 'javax.inject.Inject' annotation found and supported for autowiring around 1 before1 beforeWithParam:This is Test! MoocBiz save This is Test! around 2 around :Save Success! after: AfterReturning: Save Success! 五月 02, 2019 2:28:45 下午 org.springframework.context.support.ClassPathXmlApplicationContext doClose 信息: Closing org.springframework.context.support.ClassPathXmlApplicationContext@7fe219e7: startup date [Thu May 02 14:28:44 CST 2019]; root of context hierarchy
2.2 前置通知@before传递类参数
注解类:
package com.imooc.aop.aspectj; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 1 关于RetentionPolicy * 1.1 RetentionPolicy.SOURCE:注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃; * 1.2 RetentionPolicy.CLASS:注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期; * 1.3 RetentionPolicy.RUNTIME:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在; * SOURCE < CLASS < RUNTIME * * * 2 关于ElementType.METHOD * 2.1 * 表示注解MoocMethod能用来修饰类中的Method * * @author weijingli * */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface MoocMethod { String value(); }
切面类:
package com.imooc.aop.aspectj; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; /** * 注解切面类 * 注:本页面主要功能是:整理各种通知的注解 * @author weijingli * */ @Component @Aspect public class MoocAspect { /** * 该处设置切入点,主要是用来匹配目标对象类 * * 执行com.imooc.aop.aspect.biz 包下的 以Biz结尾的类的所有方法 */ @Pointcut("execution(* com.imooc.aop.aspectj.biz.*Biz.*(..))") public void pointcut(){} /** * 执行com.imooc.aop.aspect.biz 包下的所有类的 所有方法 */ @Pointcut("within(com.imooc.aop.aspectj.biz.*)") public void bizPointcut(){} /** * 前置通知 样例1 */ @Before("execution(* com.imooc.aop.aspectj.biz.*Biz.*(..))") public void before(){ System.out.println("before1"); } /** * AfterReturning 执行后通知,接收 目标对象返回的值 * @param reValue */ @AfterReturning(pointcut="pointcut()",returning="reValue") public void afterReturning(Object reValue){ System.out.println("AfterReturning: "+reValue); } /** * 后置通知 相当于java语法中的finally */ @After("pointcut()") public void after(){ System.out.println("after:"); } /** * 异常通知: * * 接收异常返回的信息 */ @AfterThrowing(pointcut="pointcut()",throwing="e") public void afterThrowing(RuntimeException e){ System.out.println("AfterThrowing: "+e.getMessage()); } /** * 环绕通知: * @param pjp * @return * @throws Throwable */ @Around("pointcut()") public Object around(ProceedingJoinPoint pjp) throws Throwable{ System.out.println("around 1"); Object obj = pjp.proceed(); System.out.println("around 2"); System.out.println("around :"+obj); return obj; } /** * 前置通知 带参数 */ @Before("pointcut()&&args(arg)") public void beforeWithParam(String arg){ System.out.println("beforeWithParam:"+arg); } /** * 前置通知 传入类 */ @Before("pointcut()&&@annotation(moocMethod)") public void beforeWithAnnotation(MoocMethod moocMethod){ System.out.println("beforeWithAnnotation,"+moocMethod.value()); } /** * 前置通知 样例2 */ /*@Before("pointcut()") public void before2(){ System.out.println("before2"); }*/ }
实体类:
package com.imooc.aop.aspectj.biz; import org.springframework.stereotype.Service; import com.imooc.aop.aspectj.MoocMethod; @Service public class MoocBiz { /** * 1 为什么 用 save方法 返回 String 类型? * * 答:为了方便After Or AfterReturning 通知 接收 返回值 * * 2 为什么接收String 参数? * * 答:只是为了方便测试,没有任何实际意义。 * @param arg * @return */ @MoocMethod("MoocBiz save MoocMethod") public String save(String arg){ System.out.println("MoocBiz save "+arg); // throw new RuntimeException("Save Failed!"); return "Save Success!"; } }
测试类:
package com.imooc.test.aop; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.BlockJUnit4ClassRunner; import com.imooc.aop.aspectj.biz.MoocBiz; import com.imooc.test.base.UnitTestBase; /** @RunWith 是一个运行器 * * @RunWith(JUnit4.class)就是指用JUnit4来运行 * *@RunWith(Suite.class)的话就是一套测试集合 * *@RunWith(Suite.class)的话就是一套测试集合 * *@ContextConfiguration Spring整合JUnit4测试时,使用注解引入多个配置文件 * * @author weijingli */ @RunWith(BlockJUnit4ClassRunner.class) public class TestAspectJ extends UnitTestBase{ public TestAspectJ() { super("classpath:spring-aop-aspectj.xml"); } @Test public void testAspectJ(){ MoocBiz mBiz = super.getbean("moocBiz"); mBiz.save("This is Test!"); } }
xml配置:
<?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.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd" > <!-- 自己添加注意: 1 context:component-scan 扫描包,根据注解找到通知。 使用注解的时候,记得添加扫描包的功能 2 aop:aspectj-autoproxy 通过配置织入@Aspectj切面 --> <context:component-scan base-package="com.imooc.aop.aspectj"/> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> <bean id="moocBiz" class="com.imooc.aop.aspectj.biz.MoocBiz"></bean> </beans>
打印日志:
五月 02, 2019 3:45:28 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh 信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@3f64fffc: startup date [Thu May 02 15:45:28 CST 2019]; root of context hierarchy 五月 02, 2019 3:45:28 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 信息: Loading XML bean definitions from class path resource [spring-aop-aspectj.xml] 五月 02, 2019 3:45:28 下午 org.springframework.beans.factory.support.DefaultListableBeanFactory registerBeanDefinition 信息: Overriding bean definition for bean 'moocBiz' with a different definition: replacing [Generic bean: class [com.imooc.aop.aspectj.biz.MoocBiz]; scope=singleton; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in file [F:\xiangmu3\Xin\FuQiang\Spring\ddwei-dao\target\classes\com\imooc\aop\aspectj\biz\MoocBiz.class]] with [Generic bean: class [com.imooc.aop.aspectj.biz.MoocBiz]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [spring-aop-aspectj.xml]] 五月 02, 2019 3:45:28 下午 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor <init> 信息: JSR-330 'javax.inject.Inject' annotation found and supported for autowiring around 1 before1 beforeWithAnnotation,MoocBiz save MoocMethod beforeWithParam:This is Test! MoocBiz save This is Test! around 2 around :Save Success! after: AfterReturning: Save Success! 五月 02, 2019 3:45:29 下午 org.springframework.context.support.ClassPathXmlApplicationContext doClose 信息: Closing org.springframework.context.support.ClassPathXmlApplicationContext@3f64fffc: startup date [Thu May 02 15:45:28 CST 2019]; root of context hierarchy
诸葛