使用Spring实现AOP
需要导入的依赖包
<!--Aspectj是面向切面编程(AOP)的框架,使用AOP,需要导入这个依赖包-->
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
</dependencies>
1.使用Spring的API接口实现-----MethodBeforeAdvice,AfterReturningAdvice
定义一个接口UserService
public interface UserService {
public void add();
public void delete();
public void update();
public void select();
}
实现类
public class UserServiceImpl implements UserService{
public void delete() {
System.out.println("删除了一个用户");
}
public void update() {
System.out.println("修改了一个用户");
}
public void add() {
System.out.println("增加了一个用户");
}
public void select() {
System.out.println("查询了一个用户");
}
}
定义一个日志类log和afterlog,实现spring框架中aop的接口,重点
public class log implements MethodBeforeAdvice {
/*
* method:要执行的目标对象的方法
* orgs:参数
* target:目标对象
*
* */
public void before(Method method, Object[] args, Object target) throws Throwable {
//target.getClass().getName()获取目标对象的方法名
System.out.println("log方法:"+target.getClass().getName()+"的"+method.getName()+"被执行了");
}
}
public class Afterlog implements AfterReturningAdvice {
//returnValue返回值
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("afterlog方法:"+"执行了"+method.getName()+"方法,返回的结果为"+returnValue);
}
}
配置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
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--注册bean-->
<bean id="userService" class="com.kuang.service.UserServiceImpl"></bean>
<bean id="log" class="com.kuang.log.log"></bean>
<bean id="afterlog" class="com.kuang.log.Afterlog"></bean>
<!--方式一。使用原生Spring API接口-->
<!--配置aop:需要导入aop约束-->
<aop:config>
<!--切入点:expression:表达式,execution(要执行的位置++++)
execution(* com.kuang.service.UserServiceImpl.*(..))
第一个*,代表任意的东西,
com.kuang.service.UserServiceImpl要插入的类
.*表示所有的方法,
(..)表示所有的参数
-->
<aop:pointcut id="pointcut" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/>
<!--执行环绕增加,这里的advice-ref是引用执行,上面的bean中的log,pointcut-ref是切入点-->
<aop:advisor advice-ref="log" pointcut-ref="pointcut"></aop:advisor>
<aop:advisor advice-ref="afterlog" pointcut-ref="pointcut"></aop:advisor>
</aop:config>
</beans>
测试类,**这里重点强调是代理的是接口,**可以参看动态代理章节的接口实现
public class MyTest {
public static void main(String[] args) {
ApplicationContext context= new ClassPathXmlApplicationContext("applicationContext.xml");
//这里动态代理的是接口
UserService userService = (UserService) context.getBean("userService");
userService.add();
userService.delete();
userService.update();
userService.select();
}
}
方式一结果
2.自定义来实现AOP(主要是切面定义)
自定义类DiyLog
public class DiyLog {
public void after(){
System.out.println("在方法执行之后");
}
public void before(){
System.out.println("在方法执行之前");
}
}
原来的UserService接口和UserServiceImpl实现类不变
修改xml配置文件
<bean id="userService" class="com.kuang.service.UserServiceImpl"></bean>
<bean id="log" class="com.kuang.log.log"></bean>
<bean id="afterlog" class="com.kuang.log.Afterlog"></bean>
<!--方法二,自定义类-->
<bean id="diy" class="com.kuang.diy.DiyLog"></bean>
<aop:config>
<!--自定义切面,ref要引用类-->
<aop:aspect ref="diy">
<!--切入点,execution表示这个impl类中的所有方法和参数-->
<aop:pointcut id="point" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/>
<!--通知,method就是我们自定义的方法-->
<aop:before method="before" pointcut-ref="point"></aop:before>
<aop:after method="after" pointcut-ref="point"></aop:after>
</aop:aspect>
</aop:config>
测试类不变
public class MyTest {
public static void main(String[] args) {
ApplicationContext context= new ClassPathXmlApplicationContext("applicationContext.xml");
//这里动态代理的是接口
UserService userService = (UserService) context.getBean("userService");
userService.add();
userService.delete();
userService.update();
userService.select();
}
}
3. 使用注解开发实现AOP
使用注解来开发,注意在使用注解时,@Before等切入点有两个包一定要导入aspectj包下的。
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
//使用注解方式实现AOP
@Aspect //标注这个类是一个切面
public class annotationPoint {
//用注解定义切入点
@Before("execution(* com.kuang.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("方法执行前");
}
@After("execution(* com.kuang.service.UserServiceImpl.*(..))")
public void after(){
System.out.println("方法执行后");
}
//环绕
@Around("execution(* com.kuang.service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("环绕前");
Signature signature = joinPoint.getSignature();//获得签名,
// signature:void com.kuang.service.UserService.add(),表示执行了那个方法,用于日志查看
System.out.println("signature:"+signature);
//执行方法
Object proceed = joinPoint.proceed();
System.out.println("环绕后");
System.out.println("执行:"+proceed);
}
}
###开启注解支持
<bean id="userService" class="com.kuang.service.UserServiceImpl"></bean>
<bean id="log" class="com.kuang.log.log"></bean>
<bean id="afterlog" class="com.kuang.log.Afterlog"></bean>
<!--方式三,使用注解来实现AOP-->
<!--注入bean-->
<bean id="annotationPoint" class="com.kuang.annotation.annotationPoint"></bean>
<!--开启注解支持-->
<!--代理模式有两种,基于接口动态代理(JDK-InvocationHandler),默认jdk和基于类cglib-->
<!--
proxy-target-class="false"默认JDK实现是flase
proxy-target-class="true" 是指cglib实现
两者实现效果一样
-->
<aop:aspectj-autoproxy proxy-target-class="false"></aop:aspectj-autoproxy>
使用注解开发和之前的两个方法比,
优点:代码简洁,不用在去一个一个配置bean,aop:config和aop:pointcut切入点,aop:advisor环绕
缺点:需要在每个方法上重复写execution表达式。