SpringAOP的实现

SpringAOP的实现

AOP指的是横向开发,在以前的学习中我们都是习惯于纵向开发,但是横向开发同样重要。之前的横向开发我们使用的是动态代理模式和静态代理模式,今天我们学习Spring中的AOP来实现横向开发,它的核心其实也是动态代理模式

学习AOP前的准备

1.导包

使用AOP需要导aspectjweaver

1
2
3
4
5
6
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.5.4</version>
</dependency>

2.创建学习模型

AOP官网是纯理论的东西,学习一个不熟悉的理论最好的办法就是实践,因此我们通过创建模型的方式学习AOP

搭建一个有“增删改查”功能的模型,以及我们横向开发要给每个方法加日志

使用Spring实现AOP

实现AOP的方式很多,这里我们时使用Spring自带的接口来实现AOP

Spring为我们提供了很多AOP的接口,使用方法就是把要插入的类继承各个位置的接口即可

继承抽象类

例如在方法前加方法:

继承这个接口:MethodBeforeAdvice

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.dwx.log;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class BeforLog implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {

}
}

元素分析:

  • method:要执行的目标对象的方法
  • args:参数
  • target:要执行的目标对象

这里我们要添加的是一个日志功能,具体理论就是通过method.getname()来获得执行的方法的名字即可

例如在方法后加日志:

继承AfterReturningAdvice接口

1
2
3
4
5
6
7
8
9
10
package com.dwx.log;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class EndLog implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {

}
}

元素分析:

  • method:要执行的目标对象的方法
  • args:参数
  • target:要执行的目标对象
  • returnValue:返回值

把我们创建的类都注册到日志中

  • 注册所有的类
  • 配置AOP
    • 在xml头文件中天界aop的命名空间
    • 在xml中使用<aop:xx>来使用aop
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
<?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.xsd">

<bean id="userService" class="com.dwx.service.UserServiceImpl"/>
<bean id="endBlog" class="com.dwx.log.EndLog"/>
<bean id="beforLog" class="com.dwx.log.BeforLog"/>
<!--注册完的类其实之间没有联系,需要通过xml中的AOP产生联系-->
<aop:config>
<!--切入点,表明切入点-->
<!--这句换其实是固定格式 execution(* * * *) 四个*分别代表包 类 方法 参数 全部作用用* 有限制就添加限制-->
<aop:pointcut id="pointcut" expression="execution(* com.dwx.service.UserServiceImpl.*(..))"/>
<!--执行环绕增加-->
<!--这里是注入AOP的地方 advice-ref 是我们要查如的东西 pointcut-ref 是刚才的切口即要插入的地方-->
<aop:advisor advice-ref="beforLog" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="endBlog" pointcut-ref="pointcut"/>
</aop:config>

</beans>

上边就是AOP注册到XML中的完全体,有注释解释每一步的目的

测试

测试类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import com.dwx.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
//注意这里使用的是类似于动态代理模式的AOP
//动态代理模式是作用于接口的 因此我们这里产生的对象类型应为接口
UserService userService = context.getBean("userService", UserService.class);
userService.add();
userService.delete();
userService.query();
userService.update();
}
}


结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
【DEBUG】正在执行add方法
增加了一个用户
【DEBUG】add方法执行结束返回值为:null
【DEBUG】正在执行delete方法
删除了一个用户
【DEBUG】delete方法执行结束返回值为:null
【DEBUG】正在执行query方法
查询用户为:****
【DEBUG】query方法执行结束返回值为:null
【DEBUG】正在执行update方法
更新了一个用户的信息
【DEBUG】update方法执行结束返回值为:null

Process finished with exit code 0

使用自定义类实现AOP

上边使用的AOP是使用的Spring的接口,其实还可以通过自定义类注册实现AOP

1.自定义一个类

1
2
3
4
5
6
7
8
9
10
11
package com.dwx.diy;

public class DIY {
public void before(){
System.out.println("==========程序执行开始===========");
}
public void after(){
System.out.println("==========程序执行结束===========");
}
}

2.到xml中进行注册

先注册我们的DIY类

在使用aop把DIY类中的方法切入合适的位置

此时有区别的,使用的是切面技术

1
2
3
4
5
6
7
8
9
10
<aop:config>
<!--切面,即我们的DIY类-->
<aop:aspect ref="diy">
<!--切入点-->
<aop:pointcut id="pointcut" expression="execution(* com.dwx.service.UserServiceImpl.*(..))"/>
<!--通知-->
<aop:after method="after" pointcut-ref="pointcut"/>
<aop:before method="before" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>

此时通知中包含了很多的标签,想插入哪里就使用对应的标签插入哪里

元素分析:

  • method: 这个是插入的方法,即切面(DIY类)中的方法
  • 切入点这里的所有代码和上边说的一样

执行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
==========程序执行开始===========
增加了一个用户
==========程序执行结束===========
==========程序执行开始===========
删除了一个用户
==========程序执行结束===========
==========程序执行开始===========
查询用户为:****
==========程序执行结束===========
==========程序执行开始===========
更新了一个用户的信息
==========程序执行结束===========

Process finished with exit code 0

这边可以看出,我们的DIY类实现的AOP没有使用Spring留下的接口实现的AOP强大

但是核心其实都是动态代理

使用注解实现AOP

和xml配置能被注解代替一样,Spring实现AOP也能通过注解实现

@Aspect修饰一个类,表示这个类就是一个切面

@Before("execution()")其中Before修饰的就是我们要切入的方法,execution()自然指的是接入点

例如:@Before("execution(* com.dwx.service.UserServiceImpl.*(..))")

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.dwx.diy;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class annount {
@Before("execution(* com.dwx.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("*****************");
}

}

这样子切入后也需要到xml中把这个类进行配置,并且开始自动托管事务: <aop:aspectj-autoproxy/>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?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.xsd">

<bean id="userService" class="com.dwx.service.UserServiceImpl"/>
<bean id="diy" class="com.dwx.diy.DIY"/>

<bean id="annount" class="com.dwx.diy.annount"/>
<aop:aspectj-autoproxy/>

</beans>

这样的代码会很简洁

结果:

1
2
3
4
5
6
7
8
9
10
11
*****************
增加了一个用户
*****************
删除了一个用户
*****************
查询用户为:****
*****************
更新了一个用户的信息

Process finished with exit code 0

Donate
  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.

扫一扫,分享到微信

微信分享二维码
  • Copyrights © 2015-2023 dwx
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信