1. 准备
1.1. 接口
public interface UserService {
String query();
}
1.2. 接口的实现
@Service
public class UserServiceImpl implements UserService {
@Override
public String query() {
System.out.println("------------ yz ------------");
return "yz";
}
}
1.3. 切面类
@Aspect
@Component
public class AopConfig {
@Pointcut(value = "execution(* com.atguigu.springIOC.UserServiceImpl.*(..))")
public void businessService() {
}
@Before(value = "businessService()")
public void doBefore() {
System.out.println("----------------- doBefore -----------------");
}
@AfterReturning(value = "businessService()")
public void doAfterReturning() {
System.out.println("----------------- doAfterReturning -----------------");
}
@After(value = "businessService()")
public void doAfter() {
System.out.println("----------------- doAfter -----------------");
}
}
1.4. 测试类
// 该注解在测试时必须添加;在使用 springboot 较高版本启动运行程序时,可以不添加
@EnableAspectJAutoProxy
@ComponentScan(basePackages = {
"com.atguigu.springIOC"})
public class BeanTest {
public static void main(String[] args) {
// 获取 spring IOC 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanTest.class);
// 从容器中获取 bean
UserService userService = (UserService) applicationContext.getBean("userServiceImpl");
String query = userService.query();
System.out.println(query);
}
}
1.5. 测试结果
----------------- doBefore -----------------
------------ yz ------------
----------------- doAfter -----------------
----------------- doAfterReturning -----------------
yz
2. Spring AOP
代理对象的产生
2.1. 源码解读之前
既然要产生代理对象,我们进行源码分析,无非就是从下面两行代码入手
// 获取 spring IOC 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanTest.class);
// 从容器中获取 bean
UserService userService = (UserService) applicationContext.getBean("userServiceImpl");
通过 spring 初始化 bean(单例) 过程 的文章分析,userServiceImpl
这个 bean
会通过 getBean()
从一级缓存 singletonObjects
中能获取到。那么 userServiceImpl
的代理对象肯定从下面的代码中产生
// 获取 spring IOC 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanTest.class);
2.2. 抽象类 AbstractBeanFactory
的 doGetBean()
关于代码
// 获取 spring IOC 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanTest.class);
的过程,鉴于篇幅本篇文章不再详细赘述,详细过程请查看,我们从这个 doGetBean
方法开始
@SuppressWarnings("unchecked")
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
// 通过 name 获取 beanName。这里不使用 name 直接作为 beanName 有两个原因
// 1、name 可能会以 & 字符开头,表明调用者想获取 FactoryBean 本身,而非 FactoryBean
// 实现类所创建的 bean。在 BeanFactory 中,FactoryBean 的实现类和其他的 bean 存储
// 方式是一致的,即 <beanName, bean>,beanName 中是没有 & 这个字符的。所以我们需要
// 将 name 的首字符 & 移除,这样才能从缓存里取到 FactoryBean 实例。
// 2、还是别名的问题,转换需要 &beanName
final String beanName = transformedBeanName(name);
Object bean;
// 先从缓存中获取,因为在容器初始化的时候或者其他地方调用过getBean,已经完成了初始化
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled(