文章目录
-
- aop实现方式1(实现spring接口)
-
- 导包
- 业务模块service
- 代理模块
- 测试
- Aop实现方式2(自定义切入类)
- aop实现方式3(使用注解开发)
项目地址
aop实现方式1(实现spring接口)
导包
使用之前要导入依赖包
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
</dependencies>
项目结构:
spring1-aop
├───.idea
├───src
│ ├───main
│ │ ├───java
│ │ │ └───com
│ │ │ └───ajream
│ │ │ ├───log
│ │ │ └───service
│ │ └───resources
│ └───test
└───java
业务模块service
被代理的接口,包含了要实现的具体功能
UserService.java接口:
package com.ajream.service;
public interface UserService {
void add();
void delete();
void update();
void query();
}
UserServiceImpl.java
package com.ajream.service;
public class UserServiceImpl 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 query() {
System.out.println("查询一个用户");
}
}
代理模块
在原有基础上扩展一些功能
Log.java (在实现某个业务(调用某个方法)前,打印一些相关信息)
说明:重写MethodBeforeAdvice接口的before方法,说明在切入点之前执行这个方法
package com.ajream.log;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class Log implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
assert target != null;
System.out.println(target.getClass().getName() + "的" + method.getName() + "方法被执行了");
}
}
AfterLog.java (在实现某个业务(调用某个方法)后,打印一些相关信息)
说明:重写AfterReturningAdvice的 afterReturning
方法,说明在切入点之后执行这个方法
package com.ajream.log;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class AfterLog implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("执行了" +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
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 id="userService" class="com.ajream.service.UserServiceImpl" />
<bean id="log" class="com.ajream.log.Log" />
<bean id="afterLog" class="com.ajream.log.AfterLog" />
<aop:config>
<!-- 定义切入点pointcut, execution(返回类型 包名.类名.方法名(参数)) "*"表示任意 -->
<aop:pointcut id="pointCut" expression="execution(* com.ajream.service.UserServiceImpl.*(..))"/>
<!-- 执行环绕增加-->
<aop:advisor advice-ref="afterLog" pointcut-ref="pointCut" />
<aop:advisor advice-ref="log" pointcut-ref="pointCut"/>
</aop:config>
</beans>
说明:
- 注意添加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配置(使用原生spring api接口)
<aop:config> <!--定义切入点pointcut, execution(返回类型 包名.类名.方法名(参数)) "*"表示任意 --> <aop:pointcut id="pointCut" expression="execution(* com.ajream.service.UserServiceImpl.*(..))"/> <!--执行环绕增加,即在切入点前后执行下面的操作--> <aop:advisor advice-ref="afterLog" pointcut-ref="pointCut" /> <aop:advisor advice-ref="log" pointcut-ref="pointCut"/> </aop:config>
测试
MyTest.java测试
import com.ajream.service.UserService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
//动态代理的是接口
UserService userService = context.getBean("userService", UserService.class); userService.add();
}
}
测试结果:
Aop实现方式2(自定义切入类)
主要是aop配置方式不同
之前是使用原生spring api方式,分别实现了
MethodBeforeAdvice
和
AfterReturningAdvice
这两个接口,因此在xml中只需要指明要切入哪个位置,执行什么操作,在执行目标接口的方法时spring就会根据xml配置自动去执行对应操作,如下:
<aop:config>
<!--定义切入点pointcut, execution(返回类型 包名.类名.方法名(参数)) "*"表示任意 -->
<aop:pointcut id="pointCut" expression="execution(* com.ajream.service.UserServiceImpl.*(..))"/>
<!--执行环绕增加,即在切入点前后执行下面的操作-->
<aop:advisor advice-ref="afterLog" pointcut-ref="pointCut" />
<aop:advisor advice-ref="log" pointcut-ref="pointCut"/>
</aop:config>
现在改用自定义切入面方式:
首先添加一个切面DiyPointCut(即一个类,包含了要切入的方法)
package com.ajream.diy;
//自定义切入面
public class DiyPointCut {
public void before(){
System.out.println("=====方法执行前======");
}
public void after(){
System.out.println("======方法执行后======");
}
}
aop配置:
<!--方式2:自定义类-->
<bean id="diy" class="com.ajream.diy.DiyPointCut" />
<aop:config>
<!--定义切面,ref为要引用的类-->
<aop:aspect ref="diy" >
<!--切入点-->
<aop:pointcut id="point" expression="execution(* com.ajream.service.UserServiceImpl.*(..))"/>
<!-- aop:before表示在切入点point之前执行切面的before方法-->
<aop:before method="before" pointcut-ref="point"/>
<aop:after method="after" pointcut-ref="point" />
</aop:aspect>
</aop:config>
aop实现方式3(使用注解开发)
项目地址
首先开启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
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 id="userService" class="com.ajream.service.UserServiceImpl" />
<!--方式3,注解方式-->
<bean id="annotationPointCut" class="com.ajream.diy.AnnotationPointCut" />
<!--开启aop注解支持-->
<aop:aspectj-autoproxy />
</beans>
添加切面AnnotationPointCut.java类
package com.ajream.diy;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect //标注这是一个切面
public class AnnotationPointCut {
@Before("execution(* com.ajream.service.UserServiceImpl.*(..))") //切入位置
public void before(){
System.out.println("=====方法执行前=====");
}
@After("execution(* com.ajream.service.UserServiceImpl.*(..))")
public void after(){
System.out.println("=====方法执行后=====");
}
@Around("execution(* com.ajream.service.UserServiceImpl.*(..))") //环绕增强
public void around(ProceedingJoinPoint jp) throws Throwable {
System.out.println("环绕前");
Object proceed = jp.proceed();// 执行方法
System.out.println("执行的方法签名:" + jp.getSignature());
System.out.println("环绕后");
}
}
注意,如果添加了环绕增强,首先执行环绕增强,执行了proceed方法后才会触发
@Before
这2个注解的内容,所以输出结果如下:
@After