AOP动态代理
相关术语
- 连接点
Joinpoint
- 可以被拦截的方法,即可以被增强的方法,这些方法就成为连接点
- 切入点
Pointcut
- 真正被拦截增强的方法
- 通知
Advice
- 增加的内容和功能,通常是封装的方法
- 引介
Introduction
- 类层面的增强,给原有类增加一些新的属性和方法
- 被增强的对象
Target
- 被增强的对象
- 织入
Weaving
- 将通知应用到目标对象的过程
- 代理对象
Proxy
- 代理对象
- 切入
Aspect
- 多个通知和多个切入点的集合
使用AOP的步骤
-
引用相关Spring相关jar包 -在创建spring工程的时候就自动引进了
-
引入AOP开发的相关jar包 -在创建Spring工程的时候就自动引进了
-
配置文件中引入AOP约束 -在创建Spring工程的时候就自动引进了
-
编写一个切面类
- Myaspect.java
package com.ly.test4; public class Myaspect { public void check() { System.out.println("切面类切入"); } }
-
将切面交给Spring
<!-- 将切面交给Spring管理 --> <bean id="myaspect" class="com.ly.test4.Myaspect"></bean>
-
配置AOP完成对目标的产生代理
<!-- 配置AOP完成对目标的产生和代理 --> <aop:config> <!-- 配置切点 即是哪个方法需要增强 --> <aop:pointcut id="savepoint" expression= "execution(* com.ly.test.dao.UserDaoImpl.delete(..))"></aop:pointcut> <!-- 切面配置 即增强的功能是什么 --> <aop:aspect ref="myaspect"> <!-- 前置通知--> <aop:before method="check" pointcut-ref="savepoint"></aop:before> </aop:aspect> </aop:config>
- 解析
"execution(* com.ly.test.dao.UserDaoImpl.delete(..))"
*
代表任意类型返回值..
代表任意参数
- 解析
AOP通知类型
-
前置通知
<aop:before method="check" pointcut-ref="savepoint"></aop:before>
-
后置通知 -可以接受返回值
applicationContext.xml
配置
<!-- 没有接受返回值 --> <aop:after-returning method="check" pointcut-ref="savepoint" ></aop:after-returning> <!-- 接受返回值 returning参数必须和通知接受的参数名一致 --> <aop:after-returning method="check" pointcut-ref="savepoint" returning="res"></aop:after-returning>
-
Myaspect.java
切面类需要接受参数的话public class Myaspect { public void check(String res) { System.out.println("res" + res) } }
-
环绕通知
-
需要把切入点拿到切面类中处理,然后再返回,所以切面类必须有返回值
Object
类和参数接受切入点-
Myaspect.java
public class Myaspect { public Object sorund(MethodInvocationProceedingJoinPoint joinPoint) throws Throwable { System.out.println("前置通知"); //运行传入的方法,如果不运行,则原来的方法不执行 Object proceed = joinPoint.proceed(); System.out.println("后置通知"); return proceed; } }
-
-
-
异常抛出通知
-
最终通知 -无论代码是否有异常,都会执行
-
Spring单元测试 (不是过程,是教学用的)
-
测试 (不是过程,是教学用的)
Spring单元测试
-
applicationContext.xml
<bean id="goodsDao" class="com.ly.test2.GoodsDaoImpl"></bean>
-
读取applicationContext.xml 利用注解解决
package com.ly.test4; import com.ly.test2.GoodsDao; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class AopTest { @Autowired @Qualifier("goodsDao") private GoodsDao goodsDao; @Test public void test1() { goodsDao.save(); } }
AOP开发的注解方式
-
开启注解 -示例是前置通知
-
applicationContext.xml
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
-
Aspect.java
切面类package com.ly.demo1; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; @Aspect public class Myaspect { @Before(value = "execution(* com.ly.demo1.Student.*(..))") public void check(){ System.out.println("岂可岂可岂可no"); } }
-
Student.java
被增强的对象package com.ly.demo1; import org.springframework.stereotype.Component; public class Student { public void save() { System.out.println("保存——"); } }
-
DemoTest.java
package com.ly.demo1; import org.springframework.stereotype.Component; public class Student { public void save() { System.out.println("保存——"); } }
其他注解通知
package com.ly.demo1; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; @Component("myaspect") @Aspect public class Myaspect { /** * 前置通知 */ @Before(value = "execution(* com.ly.demo1.Student.*(..))") public void check(){ System.out.println("岂可岂可岂可no"); } /** * 环绕通知 */ @Around(value = "execution(* com.ly.demo1.Student.*(..))") public Object log(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("放在前面"); Object proceed = joinPoint.proceed(); System.out.println("放在后面"); return proceed; } }
注解扩展
- 给多个方法同时设置一个通知
-
切面注入多个方法中使用和符号
||
package com.ly.demo1; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; @Component("myaspect") @Aspect public class Myaspect { /** * 前置通知 应用在多个方法之上 */ @Before(value = "execution(* com.ly.demo1.Student.save(..)) || execution(* com.ly.demo1.Student.delete(..))") public void check(){ System.out.println("岂可岂可岂可no"); }
-
设置通知名
//设置一个通知名 @Pointcut(value = "execution(* com.ly.demo1.Student.save())") private void saveAspect() {} //直接使用通知名就行了 @Around("Myaspect.saveAspect()") public Object log(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("放在前面"); Object proceed = joinPoint.proceed(); System.out.println("放在后面"); return proceed; }
-