Spring——AOP实现的三种方式
Posted 我永远信仰
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring——AOP实现的三种方式相关的知识,希望对你有一定的参考价值。
AOP实现
使用Spring实现Aop
需要导入一个依赖包
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
一、环境搭建
说明:UserService是一个接口,定义了增删改查、UserServiceImpl实现了这个接口。想要在这个基础上增加打印日志的功能,但不修改源码方法,使用Spring的AOP。这符合了OCP原则,对扩展开放,对修改关闭。
- 用到Spring的aop,aop的底层原理是代理模式。
1、UserService 接口类
package com.yong.service;
public interface UserService {
public void add();
public void update();
public void select();
public void delete();
}
2、UserServiceImpl 实现类
package com.yong.service;
public class UserServiceImpl implements UserService {
public void add() {
System.out.println("执行了add方法");
}
public void update() {
System.out.println("执行了update方法");
}
public void select() {
System.out.println("执行了select方法");
}
public void delete() {
System.out.println("执行了delete方法");
}
}
现在我需要在每一个方法执行前后都打印日志,比如执行add方法,输出
======方法执行前=====
执行了add方法
======方法执行后=====
原来的做法是修改源码
public void add() {
System.out.println("======方法执行前=====");
System.out.println("执行了add方法");
System.out.println("======方法执行后=====");
}
现在使用Spring的Aop实现。
介绍三种方法:
实现方式1
使用Spring 的API接口。
* 先创建好日志类
1.BeforeLog 前置增强日志类
package com.yong.log;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
//前置增强,需要实现对应的MethodBeforeAdvice
//Method:要执行的目标对象的方法
//args:参数
//target:目标对象
public class BeforeLog implements MethodBeforeAdvice {
public void before(Method method, Object[] args, Object target) throws Throwable {
//System.out.println("======方法执行前=====");
System.out.println("前置增强,"+o.getClass().getSimpleName()+"的"+method.getName()+"方法被执行了");
}
}
2、AfterLog 后置增强日志类
package com.yong.log;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
//后置增强
//returnValue:返回值
public class AfterLog implements AfterReturningAdvice {
public void afterReturning(Object returnValue, Method method, Object[] objects, Object o1) throws Throwable {
System.out.println("后置增强,执行了"+method.getName()+"方法,返回值为"+returnValue);
}
}
3、applicationContext.xml 配置文件
-
(1)注意命名空间也要加入aop
-
(2)注册bean
-
(3)配置切入点(在哪个地方执行)
-
理解,execution()表达式(* * * * *)
<aop:pointcut id="point" expression="execution(* com.yong.service.UserServiceImpl.*(..))"/>
id:后面的切入方法需要
com.yong.service.UserServiceImpl:类下的所有方法
(…):方法下所有的参数
<?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-->
<bean id="serviceImpl" class="com.yong.service.UserServiceImpl"/>
<bean id="log" class="com.yong.log.AfterLog"/>
<bean id="log" class="com.yong.log.BeforeLog"/>
<!--使用aop
方式一:原生Spring API接口-->
<aop:config>
<!--切入点 ,execution()表达式-->
<aop:pointcut id="point" expression="execution(* com.yong.service.UserServiceImpl.*(..))"/>
<!--执行环绕增强,将advice-ref方法插入到pointcut-ref-->
<aop:advisor advice-ref="beforeLog" pointcut-ref="point"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="point"/>
</aop:config>
</beans>
4、MyTest 测试类
- 重点 动态代理代理的是一个接口,不是一个具体的实现类。所以context.getBean() 返回的对象是一个接口类
UserService
而不是UserServiceImpl
import com.yong.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService serviceImpl = (UserService) context.getBean("serviceImpl");
serviceImpl.select();
}
}
运行结果:
实现方式2(主要是切面定义)
-
方法一有些繁琐,需要记住接口,每次也需要去实现一些接口。
-
方法二,可以自定义切入点类,能很单纯的实现在方法执行的前后打印log这两件事情。
-
比方法一使用简单,不过功能没有第一个强大,第一个能操作更多东西,但是这个一般也够用了。
-
推荐这种方法。
1、自定义类 (非常清爽)
public class DiyPointCut {
public void before(){
System.out.println("======执行方法前======");
}
public void after(){
System.out.println("======执行方法后======");
}
}
2、配置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-->
<bean id="serviceImpl" class="com.yong.service.UserServiceImpl"/>
<!--方式2:自定义类-->
<bean id="diy" class="com.yong.service.DiyPointCut"/>
<aop:config>
<!--切面,ref引用类-->
<aop:aspect ref="diy">
<!--切入点-->
<aop:pointcut id="point" expression="execution(* com.yong.service.UserServiceImpl.*(..))"/>
<!--通知
什么时候执行,执行什么方法,在哪里执行
-->
<aop:before method="before" pointcut-ref="point"/>
<aop:after method="after" pointcut-ref="point"/>
</aop:aspect>
</aop:config>
3、MyTest不变
运行结果:
实现方式3(使用注解)
1、AspectPointCut 切面类
- @Aspect : 标注这个类为一个切面
- @Before :表示切入位置,需要一个execution表达式表明切入点
package com.yong.service;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class AspectPointCut {
@Before("execution(* com.yong.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("======方法执行前=====");
}
@After("execution(* com.yong.service.UserServiceImpl.*(..))")
public void after(){
System.out.println("======方法执行后=====");
}
}
2、配置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-->
<bean id="serviceImpl" class="com.yong.service.UserServiceImpl"/>
<!--方式三:注解-->
<bean id="annotationPointcut" class="com.yong.service.AspectPointCut"/>
<!--开启注解支持-->
<aop:aspectj-autoproxy/>
</beans>
3、MyTest不变
运行结果:
以上是关于Spring——AOP实现的三种方式的主要内容,如果未能解决你的问题,请参考以下文章