介绍
- AOP被称为面向切面编程,是将横切出来的逻辑代码融合到业务逻辑中,来实现和没横切之前的一样的功能
- Spring-AOP是将相同逻辑的重复代码横向抽取出来,使用动态代理技术将这些重复代码织入到目标对象方法中,实现和原来一样的功能。
相关概念
- JoinPoint(连接点):能够被拦截到的点,在spring中,这些点指的是方法,每一个成员方法为一个连接点
- Pointcut(切点):具体定位的连接点,具体定位到某一个方法成为切点
- Advice(通知):添加到切点的一段逻辑代码,Spring中定义了五类通知
- Weave(织入):将Advice(通知)添加到目标类的具体连接点的过程
- Aspect(切面):由Pointcut(切点)和Advice(通知)组成,包括横切逻辑和连接点定义
- Target(目标对象):被代理的目标对象,已经存在的原对象
配置和使用
- 导入spring-IOC的相关jar包,还有下面这些
注解配置
- 创建xml配置文件进行包扫描和切面类
- 切入点pointcut属性配置:execution(返回值类型 包名.类名.方法名(形参类型))
- 在前置通知**@Before和最终通知@After的属性中配置的是切入点的方法**
- 在返回通知**@AfterReturning和异常通知@AfterThrowing**中
- pointcut配置的是切入点的方法
- 返回通知的returning配置的是返回值对象的名称,名称必须与形参一致,形参必须是Object
- 异常通知的throwing配置的是异常方法名称,名称必须与形参一直,形参为Exception
- 每个通知方法中的JoinPoint为接入点,即方法,可以通过属性获取到相关信息
- jp.getSignature().getName():获取到执行对象的方法名
- jp.getTarget():获取到接口的实现类
- jp.getArgs():获取方法传入的形参
- 使用环绕通知,方法的返回值必须是Object,形参必须是ProceedingJoinPoint
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| 在xml配置头中需要引入spring-aop的配置地址
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="io.jtxyh"></context:component-scan>
开启aop注解识别 , 属性 proxy-target-class: 默认false:创建代理对象,有接口的话用Proxy,没接口用cglib true:全部用cglib创建代理对象 <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| "两个注解加其他是切面bean对象" @Component @Aspect public class MyAop {
"切入点pointcut(joinPoint的集合)" "execution(返回值类型 包名.类名.方法名(形参类型))" @Pointcut("execution(* io.jtxyh.service.*.*(..))") public void servicePointcut() {}; "前置通知" @Before("servicePointcut()") public void write(JoinPoint jp) { Object target = jp.getTarget(); System.out.println("通知方法:"+target); } "返回通知" @AfterReturning(pointcut = "servicePointcut()",returning = "obj") public void afterReturn(JoinPoint jp,Object obj) { String methedName = jp.getSignature().getName(); System.out.println("返回通知:"+methedName+"-------返回信息:"+obj); } "异常通知" @AfterThrowing(pointcut = "servicePointcut()",throwing = "ex") public void afterThrow(JoinPoint jp,Exception ex) { String methedName = jp.getSignature().getName(); System.out.println("异常通知:"+methedName+"-------异常信息:"+ex.getMessage()); } "最终通知" @After("servicePointcut()") public void after(JoinPoint jp) { String methedName = jp.getSignature().getName(); System.out.println("最终通知:"+methedName); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| @Component @Aspect public class MyAop2 { @Pointcut("execution(* io.jtxyh.service.*.*(..))") public void myAop() {}; "环绕通知,方法的返回值必须是Object,形参必须是ProceedingJoinPoint" @Around("myAop()") public Object around(ProceedingJoinPoint jp) { Object target = jp.getTarget(); "impl对象" String methodName = jp.getSignature().getName(); "方法名" Object[] args = jp.getArgs(); "调用方法传入的形参" Object result = null; System.out.println("impl对象:"+target+"----方法名:"+methodName+"----方法的形参:"+Arrays.toString(args)); try { System.out.println("环绕前置通知。。。。。");
result = jp.proceed(); System.out.println("环绕后置通知"); } catch (Throwable e) { System.out.println("环绕异常通知。。。。。"); e.printStackTrace(); }finally { System.out.println("环绕结束通知"); } return result; "返回调用方法的返回值" } }
|
xml文件配置
- 定义一个普通的类,里面写上需要的方法
- 在xml文件中配置相关标签
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public class MyXmlAop { "设置前置通知" public void before(JoinPoint jp) { System.out.println("前置通知========="+jp.getSignature().getName()); } "设置返回通知方法" public void afterRu(JoinPoint jp) { System.out.println("后置通知========="+jp.getSignature().getName()); } "设置异常通知方法" public void afterThrowing(JoinPoint jp) { System.out.println("异常通知========="); } "设置最终通知" public void after(JoinPoint jp) { System.out.println("最终通知========="+jp.getSignature().getName()); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="io.jtxyh"></context:component-scan>
<aop:aspectj-autoproxy></aop:aspectj-autoproxy> 将文件加载到bean中 <bean id="myXmlAop" class="io.jtxyh.aop.MyXmlAop"></bean>
<aop:config> 通过bean找到文件 <aop:aspect ref="myXmlAop"> 指定切入点 <aop:pointcut expression="execution(* io.jtxyh.service.*.*(..))" id="myXmlPon"/> 指定前置方法 <aop:before method="before" pointcut-ref="myXmlPon"/> 指定后置通知 <aop:after-returning method="afterRu" pointcut-ref="myXmlPon"/> 指定异常通知 <aop:after-throwing method="afterThrowing" pointcut-ref="myXmlPon"/> 指定最终通知方法 <aop:after method="after" pointcut-ref="myXmlPon"/> </aop:aspect> </aop:config> </beans>
|
使用
- 注解配置和XML配置只需要使用其中一种,多配会报错
1 2 3 4 5 6 7
| public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); "必须调用的是接口,不能是impl" UserService us = ac.getBean(UserService.class); UserInfo user = us.getUser(); System.out.println("打印的返回值:"+user.toString()); }
|
相关文章
数据库连接池
SpringIOC
Junit和Spring
Tomcat
Servlet
Request,Response和ServletContext
Cookie和Session
JSP和EL和Jstl
Filter和Listener
Mybatis