尽管AOP是个好东西,但是在实例一中看来定义一个切面还是比较复杂的,需要实现专门的接口,然后进行复杂的配置。这样着实繁琐了点,好在Spring改进了这一不足,我们已经可以使用@AspectJ注解非常容易的配置定义切面。
弄一个简单的例子,着手使用@AspectJ,这里展示下pom.xml需要添加的依赖。
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjtools -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>1.8.9</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
<!-- spring 依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
package com.smart.aspectj.aspectj;
public class PersonImpl implements Person {
public void eating() {
System.out.println("我要吃饭了");
}
public void sleeping() {
System.out.println("我要睡觉了");
}
}
同样,我们需要在sleeping处织入增强。
@Aspect // 通过该注解将 PreSleepingAspect 标识为一个切面
public class PreSleepingAspect {
@Before("execution(* sleeping(..))") // 定义切点和增强类型
public void beforeSleeping() {// 增强的横切逻辑
System.out.println("睡前要刷牙两分钟!");
}
}
使用起来真的很简单,在这个横切逻辑处,我们没有继承任何接口,只是使用@Aspect注解。代码中的@Before注解则表示的这次增强类型,为前置增强,表示在目标方法执行前实施增强。execution(* sleeping(..))称之为切点表达式,execution为关键字,* sleeping(..)为操作参数。在这个实例中,execution代表目标类的某一执行方法,* sleeping(..)则是用于匹配该目标方法的字符串。
下面,我们实现为PersonImpl 生成织入PreSleepingAspect 切面的代理。
Person target = new PersonImpl();
AspectJProxyFactory factory = new AspectJProxyFactory();
// 设置目标对象
factory.setTarget(target);
// 添加切面类
factory.addAspect(PreSleepingAspect.class);
// 生成织入切面的代理对象
Person proxy = factory.getProxy();
proxy.eating();
proxy.sleeping();
运行结果如下:
效果杠杠的。
但是其实这样生成代理还是不够简洁,一般情况下,都是通过Spring的配置完成切面织入操作的。
<?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-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
<aop:aspectj-autoproxy />
<!--bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"/ -->
<bean id="person" class="com.smart.aspectj.aspectj.PersonImpl" />
<bean class="com.smart.aspectj.aspectj.PreSleepingAspect" />
</beans>
通过 aop:aspectj-autoproxy 自动为Spring容器中那些匹配@AspectJ切面的Bean创建代理,完成切面织入。
ApplicationContext context = new ClassPathXmlApplicationContext("classpath*:bean.xml");
Person target = (Person) context.getBean("person");
target.eating();
target.sleeping();
简单方便,效果一样杠杠的。
另外,如果想要在切面中获得连接点信息,添加参数类型JoinPoint
@Aspect // 通过该注解将 PreSleepingAspect 标识为一个切面
public class PreSleepingAspect {
@Before("execution(* sleeping(..))") // 定义切点和增强类型
public void beforeSleeping(JoinPoint jp) throws Throwable {// 增强的横切逻辑
// 获得目标方法所属类的类名
System.out.println(jp.getSignature().getDeclaringTypeName());
// 获得目标方法名
System.out.println(jp.getSignature().getName());
// 获得目标参数
System.out.println(jp.getArgs());
System.out.println("睡前要刷牙两分钟!");
}
}
JoinPoint对象封装了SpringAop中切面方法的信息,在切面方法中添加JoinPoint参数,就可以获取到封装了该方法信息的JoinPoint对象.
常用api:
方法名 功能
Signature getSignature(); 获取封装了署名信息的对象,在该对象中可以获取到目标方法名,所属类的Class等信息
Object[] getArgs(); 获取传入目标方法的参数对象
Object getTarget(); 获取被代理的对象
Object getThis(); 获取代理对象
ProceedingJoinPoint对象
ProceedingJoinPoint对象是JoinPoint的子接口,该对象只用在@Around的切面方法中,
添加了
Object proceed() throws Throwable //执行目标方法
Object proceed(Object[] var1) throws Throwable //传入的新的参数去执行目标方法