SpringAOP

介绍

  1. AOP被称为面向切面编程,是将横切出来的逻辑代码融合到业务逻辑中,来实现和没横切之前的一样的功能
  2. Spring-AOP是将相同逻辑的重复代码横向抽取出来,使用动态代理技术将这些重复代码织入到目标对象方法中,实现和原来一样的功能。

相关概念

  1. JoinPoint(连接点):能够被拦截到的点,在spring中,这些点指的是方法,每一个成员方法为一个连接点
  2. Pointcut(切点)具体定位的连接点,具体定位到某一个方法成为切点
  3. Advice(通知):添加到切点的一段逻辑代码,Spring中定义了五类通知
    • 前置通知
    • 后置通知
    • 返回通知
    • 异常通知
    • 环绕通知
  4. Weave(织入):将Advice(通知)添加到目标类具体连接点的过程
  5. Aspect(切面):由Pointcut(切点)Advice(通知)组成,包括横切逻辑和连接点定义
  6. Target(目标对象):被代理的目标对象,已经存在的原对象

配置和使用

  • 导入spring-IOC的相关jar包,还有下面这些
    spring-aopJar.png

注解配置

  1. 创建xml配置文件进行包扫描切面类
  2. 切入点pointcut属性配置:execution(返回值类型 包名.类名.方法名(形参类型))
  3. 在前置通知**@Before和最终通知@After的属性中配置的是切入点的方法**
  4. 在返回通知**@AfterReturning和异常通知@AfterThrowing**中
    • pointcut配置的是切入点的方法
    • 返回通知的returning配置的是返回值对象的名称,名称必须与形参一致形参必须是Object
    • 异常通知的throwing配置的是异常方法名称,名称必须与形参一直形参为Exception
  5. 每个通知方法中的JoinPoint为接入点,即方法,可以通过属性获取到相关信息
    • jp.getSignature().getName():获取到执行对象的方法名
    • jp.getTarget():获取到接口的实现类
    • jp.getArgs():获取方法传入的形参
  6. 使用环绕通知,方法的返回值必须是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 // 日志切面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
// 切面bean对象
@Component // 实现被包扫描扫描到
@Aspect // 日志切面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文件配置

  1. 定义一个普通的类,里面写上需要的方法
  2. 在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