AOP简析
AOP面向切面编程即基于代理实现的对方法进行拦截的过程。
常用名词
Aspect切面:实际就是真正拦截调用的方法
PointCut切点:所需拦截的位置、方法,即拦截点
Target对象:需要被拦截、代理的对象
AOP使用
导入依赖
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
被代理对象及其实现类
public interface UserService {
void add();
void delete();
void select();
void update();
}
public class UserServiceImpl implements UserService{
@Override
public void add() {
System.out.println("add");
}
@Override
public void delete() {
System.out.println("delete");
}
@Override
public void select() {
System.out.println("select");
}
@Override
public void update() {
System.out.println("update");
}
}
方法一 Spring的API接口(即使用Spring预先设置好的拦截接口)
借助Spring的接口实现AOP:
前向拦截:
public class Log implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println(o.getClass().getName() + " " + method.getName());
}
}
后向拦截:
public class AfterLog implements AfterReturningAdvice {
@Override
public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
System.out.println(method.getName() + " return " + o);
}
}
配置文件中设置切入点等
<?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">
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* com.lms.service.UserServiceImpl.*(..))"/>
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
</aop:config>
<beans>
<bean id="userService" class="com.lms.service.UserServiceImpl"/>
<bean id="log" class="com.lms.log.Log"/>
<bean id="afterLog" class="com.lms.log.AfterLog"/>
</beans>
</beans>
aop:config表示需要进行AOP设置的模块
aop:pointcut表示此处是切入点,即需要被代理的对象,expression="execution(* com.lms.service.UserServiceImpl.*(..))"
此处表示需要被拦截的部分,即其下所有方法
aop:advisor表示所有用于拦截的方法及其应用的切入点对应关系。
测试
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserService userService = (UserService) context.getBean("userService");
userService.add();
}
和正常Spring获取Bean方式相同,只是getBean时,需要用接口承接结果而不是其实现类
输出效果
com.lms.service.UserServiceImpl add
add
add return null
方法二 自定义拦截类(切面)
自定义切面
public class DiyPointCut {
public void before() {
System.out.println("执行前");
}
public void after() {
System.out.println("执行完成");
}
}
配置拦截
<bean id="userService" class="com.lms.service.UserServiceImpl"/>
<bean id="diy" class="com.lms.diy.DiyPointCut"/>
<aop:config>
<aop:aspect ref="diy">
<aop:pointcut id="point" expression="execution(* com.lms.service.UserServiceImpl.*())"/>
<aop:before method="before" pointcut-ref="point"/>
<aop:after method="after" pointcut-ref="point"/>
</aop:aspect>
</aop:config>
和方法一配置方式类似,只是深入aop:aspect这个切面进行定制配置
aop:before和after一样,对应method就是自定义切面中实现的方法名
方法三 注解实现
创建注解配置类
此处借助注解编写切面,和xml配置大同小异
@Aspect
public class AnnotationPointCut {
@Before("execution(* com.lms.service.UserServiceImpl.*())")
public void before() {
System.out.println("执行前");
}
@After("execution(* com.lms.service.UserServiceImpl.*())")
public void after() {
System.out.println("执行完成");
}
@Around("execution(* com.lms.service.UserServiceImpl.*())")
public void around(ProceedingJoinPoint jp) throws Throwable {
System.out.println("环绕前");
Object proceed = jp.proceed();
System.out.println("环绕后");
}
}
在配置中注册所需类
<bean id="userService" class="com.lms.service.UserServiceImpl"/>
<bean id="annoCut" class="com.lms.diy.AnnotationPointCut"/>
<aop:aspectj-autoproxy/>