面向切面编程
Posted xuweiweiwoaini
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面向切面编程相关的知识,希望对你有一定的参考价值。
1 AOP概述
1.1 什么是AOP?
- AOP,全称是Aspect Oriented Programming,即面向切面编程。
- 简单的说,AOP就是讲我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源代码的情况下,对我们已有的方法进行增强。
1.2 AOP的作用和优势
1.2.1 AOP的作用
- 在程序运行期间,不修改源代码对已有方法进行增强。
1.2.2 AOP的优势
- 减少重复代码。
- 提高开发效率。
- 维护方便。
1.3 AOP的实现方式
- 使用动态代理技术。
2 Spring中的AOP
2.1 Spring中AOP的细节
2.1.1 AOP的相关术语
- Joinpoint(连接点):所谓连接点是指那些被拦截的点。在Spring中,这些点指的是方法,因为SPring只支持方法类型的连接点。
- Pointcut(切入点):所谓切入点是指我们要对那些Jointpoint进行拦截的定义。
- Advice(通知/增强):
- 所谓通知是指拦截到Joinpoint之后所要做的事情就是通知。
- 通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。
- Target(目标):代理的目标对象。
- Weaving(织入):是指把藏青应用到目标对象来创建新的代理对象的过程。Spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入。
- Proxy(代理):一个类被AOP织入增强后,就产生了一个结果代理类。
- Aspect(切面):是切入点和通知的结合。
2.2 基于XML的AOP配置
2.2.1 导入相关依赖jar包的maven坐标
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.0.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.2.0.RELEASE</version> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.17</version> </dependency> <dependency> <groupId>commons-dbutils</groupId> <artifactId>commons-dbutils</artifactId> <version>1.7</version> </dependency> <dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>0.9.5.4</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>5.2.0.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>5.2.0.RELEASE</version> </dependency> <dependency> <groupId>aopalliance</groupId> <artifactId>aopalliance</artifactId> <version>1.0</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.4</version> </dependency>
2.2.2 LogUtils
package com.sunxiaping.spring5.log; /** * 日志,即通知 */ public class LogUtils { /** * 开始打印日志 */ public void startLog() { System.out.println("****开始打印日志****"); } /** * 结束打印日志 */ public void endLog() { System.out.println("****结束打印日志****"); } }
2.2.3 编写业务层代码
- IAccountService.java
package com.sunxiaping.spring5.service; public interface IAccountService { /** * 新增 */ void save(); /** * 更新 */ void update(); }
- AccoutServiceImpl.java
package com.sunxiaping.spring5.service.impl; import com.sunxiaping.spring5.service.IAccountService; public class AccountServiceImpl implements IAccountService { @Override public void save() { System.out.println("新增"); } @Override public void update() { System.out.println("根据"); } }
2.2.4 创建applicationContex.xml并配置
- applicationContext.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" 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="accountService" class="com.sunxiaping.spring5.service.impl.AccountServiceImpl"/> <!-- 配置通知 --> <bean id="log" class="com.sunxiaping.spring5.log.LogUtils"></bean> <!-- 配置aop--> <aop:config> <!-- 配置切入点表达式--> <aop:pointcut id="pointcut" expression="execution(* com.sunxiaping.spring5.service.*.*(..))"/> <!-- 配置切面 id:给切面提供一个唯一的id ref:引用配置好的通知类Bean的id --> <aop:aspect ref="log"> <!-- 前置通知 --> <aop:before method="startLog" pointcut-ref="pointcut"/> <!-- 后置通知 --> <aop:after method="endLog" pointcut-ref="pointcut"/> </aop:aspect> </aop:config> </beans>
2.2.5 测试
- 示例:
package com.sunxiaping; import com.sunxiaping.spring5.service.IAccountService; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:applicationContext.xml") public class spring5Test { @Autowired private IAccountService accountService; @Test public void test() { accountService.save(); } }
2.3 基于注解的AOP配置
2.3.1 业务层配置注解
- IAccountService.java
package com.sunxiaping.spring5.service; public interface IAccountService { /** * 新增 */ void save(); /** * 更新 */ void update(); }
- AccountServiceImpl.java
package com.sunxiaping.spring5.service.impl; import com.sunxiaping.spring5.service.IAccountService; import org.springframework.stereotype.Service; @Service public class AccountServiceImpl implements IAccountService { @Override public void save() { System.out.println("新增"); } @Override public void update() { System.out.println("根据"); } }
2.3.2 配置通知
- 示例:
package com.sunxiaping.spring5.log; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; /** * 日志,即通知 */ @Component @Aspect //表明是一个通知类 public class LogUtils { @Pointcut("execution(* com.sunxiaping.spring5.service.*.*(..))") public void pointcut() { } /** * 开始打印日志 */ @Before("pointcut()") public void startLog() { System.out.println("****开始打印日志****"); } /** * 结束打印日志 */ @After("pointcut()") public void endLog() { System.out.println("****结束打印日志****"); } }
2.3.3 创建并配置applicationContext.xml
- applicationContex.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:context="http://www.springframework.org/schema/context" 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/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <context:component-scan base-package="com.sunxiaping.spring5"/> <!--开启Spring对注解AOP的支持--> <aop:aspectj-autoproxy/> </beans>
2.3.4 测试
- 示例:
package com.sunxiaping; import com.sunxiaping.spring5.service.IAccountService; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:applicationContext.xml") public class spring5Test { @Autowired private IAccountService accountService; @Test public void test() { accountService.save(); } }
2.4 基于纯注解的AOP配置
2.4.1 配置业务层注解
- IAccountService.java
package com.sunxiaping.spring5.service; public interface IAccountService { /** * 新增 */ void save(); /** * 更新 */ void update(); }
- AccountServiceImpl.java
package com.sunxiaping.spring5.service.impl; import com.sunxiaping.spring5.service.IAccountService; import org.springframework.stereotype.Service; @Service public class AccountServiceImpl implements IAccountService { @Override public void save() { System.out.println("新增"); } @Override public void update() { System.out.println("根据"); } }
2.4.2 配置通知
- LogUtils.java
package com.sunxiaping.spring5.log; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; /** * 日志,即通知 */ @Component @Aspect //表明是一个通知类 public class LogUtils { @Pointcut("execution(* com.sunxiaping.spring5.service.*.*(..))") public void pointcut() { } /** * 开始打印日志 */ @Before("pointcut()") public void startLog() { System.out.println("****开始打印日志****"); } /** * 结束打印日志 */ @After("pointcut()") public void endLog() { System.out.println("****结束打印日志****"); } }
2.4.3 配置SpringConfiguration.java文件
- SpringConfiguration.java
package com.sunxiaping.spring5.config; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; @Configuration @ComponentScan(basePackages = "com.sunxiaping.spring5") @EnableAspectJAutoProxy public class SpringConfiguration { }
2.4.4 测试
- 示例:
package com.sunxiaping; import com.sunxiaping.spring5.config.SpringConfiguration; import com.sunxiaping.spring5.service.IAccountService; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = SpringConfiguration.class) public class spring5Test { @Autowired private IAccountService accountService; @Test public void test() { accountService.save(); } }
以上是关于面向切面编程的主要内容,如果未能解决你的问题,请参考以下文章