文章目录
Spring AOP
一. 概述
1. Aop简介
AOP为Aspect Oriented Programming 即面向切面编程,可以说是对面向对象编程(OOP的一种补充)扩展和延伸,是为了解决OOP中产生的开发问题。
2. OOP和AOP
软件开发一直在寻求一种高效开发、护展、维护的方式。从面向过程的开发实践中,前人针对业务处理过程的实体及其属性和行为进行抽象封装,以获得更加清晰高效的逻辑单元划分,形成了面向对象的开发思想(OOP)
例如我们在操作Controller、Server、Dao的时候,面向对象虽然会很好地解决了业务级别的开发。但是于系统级别的开发我们很难聚焦。比如、对于每一个模块需要进行打日志、代码监控、异常处理。以日志为例,如果以OOP的思想,每个层都抽象出方法去实现日志功能,会产生很强的耦合,为了能够更好地将系统级别的代码抽离出来,去掉与对象的耦合,所以用到了AOP
所以
- AOP是对OOP的补充
- OOP是将程序分解成各个层次的对象,面向业务中的名词领域,侧重点在与抽象
- AOP是将程序运行过程分解成各个切面,从程序运行角度考虑程序的结构,面向业务中的动词领域,侧重点在于解耦
3. AOP主要的特点
源码无关性:在不改变源码的前提下,给程序动态统一添加功能
隔离性:低耦合
二 在idea里创建Spring项目
1. 新建spring项目(熟悉的可以直接跳过)
勾选Spring以及Web Application(其他保持默认状态)
选择项目名称与项目路径——点击Finish(会自动下载spring需要的jar包)
新建配置文件(Spring Conifg文件)
2.到官网下载aspect相关的jar包
Spring中进行aop操作除了导入基本的jar包,还需要导入aop相关jar包
下载地址
- 然后将jar包移动至lib下
- 在添加了jar包后,并不会自动给我们build进去,需要手动build。
选择lib中刚刚导入的jar包。
三 简单AOP实现
Spring 方面可以使用下面提到的五种通知工作:
通知 | 描述 |
---|---|
前置通知 | 在一个方法执行之前,执行通知。 |
后置通知 | 在一个方法执行之后,不考虑其结果,执行通知。 |
返回后通知 | 在一个方法执行之后,只有在方法成功完成时,才能执行通知。 |
抛出异常后通知 | 在一个方法执行之后,只有在方法退出抛出异常时,才能执行通知。 |
环绕通知 | 在建议方法调用之前和之后,执行通知。 |
1. xml式
- spring的xml配置文件application.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="userDao" class="demo.UserDao"></bean>
<!-- 配置切面类 -->
<bean id="userAspect" class="demo.Aspect.UserAspectXML"></bean>
<!-- 配置 AOP -->
<aop:config>
<!-- 配置切点表达式 -->
<!--
整个表达式可以分为五个部分:
1、execution()::表达式主体。
2、第一个*号:表示返回类型, *号表示所有的类型。
3、包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,com.sample.service包、子孙包下所有类的方法。
4、第二个*号:表示类名,*号表示所有的类。
5、*(..):最后这个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数
-->
<!-- 配置切点 -->
<aop:pointcut expression="execution(* demo.UserDao.saveUser(..))" id="pointcut1" />
<aop:pointcut expression="execution(* demo.UserDao.deleteUser(..))" id="pointcut2" />
<aop:pointcut expression="execution(* demo.UserDao.updateUser(..))" id="pointcut3" />
<aop:pointcut expression="execution(* demo.UserDao.queryUser(..))" id="pointcut4" />
<!-- 配置切面及通知 -->
<aop:aspect ref="userAspect">
<!-- 前置通知 -->
<aop:before method="before" pointcut-ref="pointcut1" />
<!-- 后置通知 -->
<aop:after method="after" pointcut-ref="pointcut2" />
<!-- 环绕通知-->
<aop:around method="around" pointcut-ref="pointcut3" />
<!-- 异常抛出通知 -->
<aop:after-throwing method="afterThrowing" pointcut-ref="pointcut4" throwing="e" />
<!-- 返回通知 -->
<aop:after-returning method="afterReturning" pointcut-ref="pointcut4" returning="result" />
</aop:aspect>
</aop:config>
</beans>
- 目标类UserDao代码如下:
package demo;
/**
* @version 1.0
* @author: lixiaoli
* @ClassName: UserDao
* @ProjectName springDemo2
* @date 2019/1/30 15:14
*/
public class UserDao {
public void saveUser(){
System.out.println("=======save========");
System.out.println("save完成");
}
public void updateUser(String name){
System.out.println("=======update========"+name);
System.out.println("update完成");
}
public void deleteUser(){
System.out.println("=======delete========");
System.out.println("delete完成");
}
public String queryUser() {
System.out.println("=======query========");
System.out.println("query完成");
return "李小立";
}
}
- 切面类UserAspectXML,可以设置切面中五种不同的通知方法。
package demo.Aspect;
import org.aspectj.lang.ProceedingJoinPoint;
/**
* @version 1.0
* @author: lixiaoli
* @ClassName: UserAspectXML
* @ProjectName springDemo2
* @date 2019/1/30 15:15
*/
public class UserAspectXML {
// 前置通知
public void before() {
System.out.println("前置通知===========");
}
// 后置通知:
public void after() {
System.out.println("后置通知============");
}
// 环绕通知:
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕前通知==========");
Object obj = joinPoint.proceed();
System.out.println("环绕后通知==========");
return obj;
}
// 异常抛出通知:
public void afterThrowing(Throwable e) {
System.out.println("异常抛出通知=========" + e.getMessage());
}
//返回通知
public void afterReturning(Object result) {
System.out.println("返回通知===========" + result);
}
}
- 最后在新建一个演示类DemoMainXML
public class DemoMainXML {
public static void main(String[] args) {
ApplicationContext app=new ClassPathXmlApplicationContext("application.xml");
UserDao userDao = (UserDao)app.getBean("userDao");
//userDao.saveUser();
//userDao.deleteUser();
userDao.updateUser("小立");
//userDao.queryUser();
}
}
得到结果:
2. 注解式
-
SpringAOP中的注解
@Aspect声明这是一个切面类
支持 5 种类型的通知注解:
@Before: 前置通知, 在方法执行之前执行
@After: 后置通知, 在方法执行之后执行
@Around: 环绕通知, 围绕着方法执行
@AfterThrowing: 异常通知, 在方法抛出异常之后
@AfterRunning: 返回通知, 在方法返回结果之后执行 -
spring的配置文件-----application2.xml 开启注解的AOP的开发
<?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="userDao" class="demo.UserDao"></bean>
<!-- 配置切面类 -->
<bean id="userAspectA" class="demo.Aspect.UserAspectA"></bean>
<!-- 在配置文件中开启注解的AOP的开发 -->
<aop:aspectj-autoproxy/>
</beans>
- UserDao类同上述xml方式的。
@Aspect
public class UserAspectA {
// 前置通知:
@Before(value = "UserAspectA.pointcut1()")
public void before() {
System.out.println("前置通知===========");
}
// 后置通知:
@After(value = "UserAspectA.pointcut2()")
public void after() {
System.out.println("后置通知============");
}
// 环绕通知:
@Around(value = "UserAspectA.pointcut3()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕前通知==========");
Object obj = joinPoint.proceed();
System.out.println("环绕后通知==========");
return obj;
}
// 异常抛出通知:
@AfterThrowing(value = "UserAspectA.pointcut4()", throwing = "e")
public void afterThrowing(Throwable e) {
System.out.println("异常抛出通知=========" + e.getMessage());
}
//返回通知
@AfterReturning(value = "UserAspectA.pointcut4()", returning = "result")
public void afterReturning(Object result) {
System.out.println("返回通知===========" + result);
}
// 切入点注解:
@Pointcut(value = "execution(* demo.UserDao.saveUser(..))")
private void pointcut1() {
}
@Pointcut(value = "execution(* demo.UserDao.deleteUser(..))")
private void pointcut2() {
}
@Pointcut(value = "execution(* demo.UserDao.updateUser(..))")
private void pointcut3() {
}
@Pointcut(value = "execution(* demo.UserDao.queryUser(..))")
private void pointcut4() {
}
}
- 新建一个演示类DemoMainA
public class DemoMainA {
public static void main(String[] args){
ApplicationContext app=new ClassPathXmlApplicationContext("application2.xml");
UserDao userDao = (UserDao)app.getBean("userDao");
userDao.saveUser();
//userDao.deleteUser();
userDao.updateUser("小立");
userDao.queryUser();
}
}
得到结果与XML方式AOP完全一致。
版权声明:本文为博主原创文章,未经博主允许不得转载 https://blog.csdn.net/qq_44614710/article/details/86763057