1、什么是AOP
全称是 Aspect Oriented Programming 即:面向切面编程。是OOP(面向对象编程)的延续,也是Spring框架中的一个重要内容,是函数式编程的一种衍生泛型。简单的说他就是把我们程序重复的代码抽取出来,在需要执行的时候使用动态代理技术在不修改源码的基础上,对我们的已有方法进行增强。
AOC在Spring中的作用
2、使用Spring实现AOP
方式一:使用Spring的API接口来做
1、导入AOP支持
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.19</version>
<scope>runtime</scope>
</dependency>
2、创建测试类
抽象类:
package com.li.service;
public interface UserService {
public void add();
public void delete();
public void update();
public void select();
}
抽象类实现:
package com.li.service;
public class UserServiceImp implements UserService{
@Override
public void add() {
System.out.println("增加");
}
@Override
public void delete() {
System.out.println("删除");
}
@Override
public void update() {
System.out.println("修改");
}
@Override
public void select() {
System.out.println("查询");
}
}
3、创建切面类,编写切面方法
方法一:实现MethodBeforeAdvice 在切入点之前切入方法
package com.li.log;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class Log implements MethodBeforeAdvice {
//实现MethodBeforeAdvice会在方法执行前运行
//method: 要执行的目标对象的方法
//args:参数
//target:目标对象
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(target.getClass().getName()+"的"+method.getName()+"方法被执行了,"+"参数是:"+args.getClass().getName());
}
}
方法二:实现 AfterReturningAdvice 在切入点后加入切面方法
package com.li.log;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class AfterLog implements AfterReturningAdvice {
//实现AfterReturningAdvice会在方法执行后执行
//method: 要执行的目标对象的方法
//args:参数
//target:目标对象
//返回值:returnValue
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println(target.getClass().getName()+"执行了:"+method.getName()+"方法,方法参数是:"+args.getClass().toString()+"返回值是:"+returnValue);
}
}
4、创建配置文件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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--注册Bean-->
<bean id="UserService" class="com.li.service.UserServiceImp"/>
<bean id="log" class="com.li.log.Log"/>
<bean id="AfterLog" class="com.li.log.AfterLog"/>
<!--使用原生Spring api接口-->
<!--配置aop: 需要先导入aop的约束 xmlns:aop="http://www.springframework.org/schema/aop" http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd"-->
<aop:config>
<!--需要一个切入点就是我们需要在什么地方去执行我们的Spring的方法-->
<!--id后面接你想给切入点取的名字 expression需要接表达式,表达式是死的:execution(* 要执行的位置.*(..)) 这里的.*表示位置下的所有方法 (..)表示可以有任意的参数-->
<aop:pointcut id="poi" expression="execution(* com.li.service.UserServiceImp.*(..))"/>
<!--执行环绕增强-->
<aop:advisor advice-ref="log" pointcut-ref="poi"/>
<aop:advisor advice-ref="AfterLog" pointcut-ref="poi"/>
</aop:config>
</beans>
5、测试类测试
package com.li.log;
import com.li.service.UserService;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestGo {
@Test
public void test1(){
//通过配置文件获取ClassPath
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//根据抽象类获取Bean
UserService user = context.getBean("UserService", UserService.class);
//调用方法测试
user.add();
}
}
测试结果
方式二:使用自定义类来实现Aop
创建自定义类和方法
package com.li.diy;
public class Diy {
public void before(){
System.out.println("====切面之前执行====");
}
public void after(){
System.out.println("====切面之后执行====");
}
}
配置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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--注册Bean-->
<bean id="UserService" class="com.li.service.UserServiceImp"/>
<!--方式二: 通过自定义方法来Aop-->
<!--注册Bean-->
<bean id="diy" class="com.li.diy.Diy"/>
<!--配置aop: 需要先导入aop的约束 xmlns:aop="http://www.springframework.org/schema/aop" http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd"-->
<aop:config>
<!--自定义切面,ref:接需要引用类的bean id-->
<aop:aspect ref="diy">
<!--id后面接你想给切入点取的名字 expression需要接表达式,表达式是死的:execution(* 要执行的位置.*(..)) 这里的.*表示位置下的所有方法 (..)表示可以有任意的参数-->
<aop:pointcut id="point" expression="execution(* com.li.service.UserServiceImp.*(..))"/>
<!--通知 method后接前面类中自定义的方法名 pointcut-ref后接切入点的id -->
<aop:before method="before" pointcut-ref="point"/>
<aop:after method="after" pointcut-ref="point"/>
</aop:aspect>
</aop:config>
</beans>
创建测试类
package com.li.log;
import com.li.service.UserService;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestGo {
@Test
public void test1(){
//通过配置文件获取ClassPath
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//根据抽象类获取Bean
UserService user = context.getBean("UserService", UserService.class);
//调用方法测试
user.add();
}
}
测试结果