AOP切面编程思想
AOP即 (Aspect Oriented Programming)面向切面编程
- 目的是在不修改原来代码的基础上添加某种额外的功能
可以理解为以前都是排一行队,现在想在第某行添加一个管理者,让其管理某个(或多个)人,所以让其并列到该位置即可。
润物细无声的执行,而在业务代码中没有表现出来,直接通过配置就能够动态的获得对象,并执行。
- 优点:不用在原来的代码上修改,下次也容易找到,修改一处,多处使用,降低了代码的耦合度
- 缺点:配置文件任务重
与OOP编程思想比较来看,aop可以看做是对oop的补充和完善。
AOP编程思想在spring中应的比较广泛
已经完成的业务
- dao层
package com.wenhua.spring.dao;
import org.springframework.stereotype.Repository;
@Repository(value = "userDao")
public class UserDao {
/**
* 当我们业务功能实现后,后期添加一些新的功能(与业务关系不大)
* 记录每次操作后的日志信息
* 开启事务
* 提交事务
*/
public void insert() {
System.out.println("保存用户");
}
public void update() {
System.out.println("修改用户");
// 一般情况 直接添加到业务代码中,而且代码不断的要重复
// LogUtil.saveLog();
}
public void find() {
System.out.println("查询用户");
int num = 10/0;
// LogUtil.saveLog();
}
}
- service层
package com.wenhua.spring.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.wenhua.spring.dao.UserDao;
/**
* 用户服务层
* @author ASUS
*
*/
@Service(value="userService")
public class UserService {
@Autowired// spring中自动注入,根据UserDao类型去Spring容器中寻找UserDao中可以没有标签和set和get方法
private UserDao userDao;
public void save(){
userDao.insert();
}
public void update(){
userDao.update();
}
public void find(){
userDao.find();
}
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
- test层
package com.wenhua.spring.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.wenhua.spring.service.UserService;
public class UserTest {
public static void main(String[] args) {
// 加载spring配置文件,创建一个ApplicaionContext
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
// 此测试方法可以没有User类
UserService userService = context.getBean(UserService.class);
userService.save();
System.out.println("--------环绕通知--------------");
userService.update();
System.out.println("----------注意异常通知不要和环绕通知一起用-------------");
userService.find();
}
}
实现aop切面编程
- 在pom.xml配置文件中添加jar包
<!-- spring切面实现 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
- 在.xml配置文件中添加响应功能的约束
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
- 编写将要通知的类(logUtil)以及方法
package com.wenhua.spring.util;
import org.aspectj.lang.ProceedingJoinPoint;
public class LogUtil {
// 定义为静态的,便于在其他业务类中调用
public static void saveLog(){
System.out.println("保存日志");
}
// 环绕通知
public void aroundAdvice(ProceedingJoinPoint point){
System.out.println("开启事务");
try {
point.proceed();
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("提交事务");
}
// 异常通知
public static void exceptionAdvice(Throwable e){
System.out.println("异常通知"+e.getMessage());
}
}
通过bean标签将该类注入到spring框架中,以供使用
<!-- 配置装有公共功能的切面LogUtil对象 -->
<bean id="logUtil" class="com.wenhua.spring.util.LogUtil"></bean>
- 在配置文件中进行织入配置
<!-- 织入 -->
<aop:config>
<!-- 配置切入点 -->
<aop:pointcut expression="execution(* com.wenhua.spring.dao.UserDao.insert(..))" id="insert"/>
<aop:pointcut expression="execution(* com.wenhua.spring.dao.UserDao.update(..))" id="update"/>
<aop:pointcut expression="execution(* com.wenhua.spring.dao.UserDao.find(..))" id="find"/>
<!-- 对该类下的所有方法进行统一配置
<aop:pointcut expression="execution(* com.wenhua.spring.dao.UserDao.*(..))" id="all"/> -->
<!-- 配置通知和切入点 -->
<aop:aspect ref="logUtil">
<!-- 在执行事务之前 -->
<!-- <aop:before method="saveLog" pointcut-ref="insert"/> -->
<!-- 在执行事务之后 -->
<aop:after method="saveLog" pointcut-ref="insert"/>
<!-- 环绕通知 -->
<aop:around method="aroundAdvice" pointcut-ref="update"/>
<!-- 异常通知 -->
<aop:after-throwing method="exceptionAdvice" pointcut-ref="find" throwing="e"/>
</aop:aspect>
</aop:config>
名词解释
- 连接点(Joinpoint): 类中可以被增强的方法
- 切入点(poincut): 类中已经被增强了的方法
- 通知(Advice): 切面要完成的工作(额外的工作)
- 切面(Aspect): 把通知添加到切入点的过程
- 目标(Target): 代理的目标对象(要增强的类)
- 织入(Weaving): 将通知应用到目标的过程
- 代理(Proxy): 向目标对象应用通知之后创建的代理对象