由于 AOP 是基于 Spring 容器管理的 bean 做的增强,所以整个工作过程需要从 Spring 加载 bean 说起:
ptx()
并没有被使用,所以不会被读取。判定 bean 对应的类中的方法是否匹配到任意切入点
UserDao
BookDao
为了验证 IOC 容器中创建的对象和我们刚才所说的结论是否一致,首先先把结论理出来:
1.要执行的方法,不被定义的切入点包含,即不要增强,打印当前类的 getClass()方法 2.要执行的方法,被定义的切入点包含,即要增强,打印出当前类的 getClass()方法 3.观察两次打印的结果
public class App {
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
BookDao bookDao = ctx.getBean(BookDao.class);
System.out.println(bookDao);
System.out.println(bookDao.getClass());
}
}
因为定义的切入点中,被修改成update1
,所以 BookDao 中的 update 方法在执行的时候,就不会被增强,
所以容器中的对象应该是目标对象本身。
@Component
@Aspect
public class MyAdvice {
@Pointcut("execution(void com.itheima.dao.BookDao.update1())")
private void pt(){}
@Before("pt()")
public void method(){
System.out.println(System.currentTimeMillis());
}
}
因为定义的切入点中,被修改成update
,所以 BookDao 中的 update 方法在执行的时候,就会被增强,
所以容器中的对象应该是目标对象的代理对象
@Component
@Aspect
public class MyAdvice {
@Pointcut("execution(void com.itheima.dao.BookDao.update())")
private void pt(){}
@Before("pt()")
public void method(){
System.out.println(System.currentTimeMillis());
}
}
至此对于刚才的结论,我们就得到了验证,这块大家需要注意的是:
不能直接打印对象,从上面两次结果中可以看出,直接打印对象走的是对象的 toString 方法,不管是不是代理对象打印的结果都是一样的,原因是内部对 toString 方法进行了重写。
在上面介绍 AOP 的工作流程中,我们提到了两个核心概念,分别是:
上面这两个概念比较抽象,简单来说,
目标对象就是要增强的类[如:BookServiceImpl 类]对应的对象,也叫原始对象,不能说它不能运行,只能说它在运行的过程中对于要增强的内容是缺失的。
SpringAOP 是在不改变原有设计(代码)的前提下对其进行增强的,它的底层采用的是代理模式实现的,所以要对原始对象进行增强,就需要对原始对象创建代理对象,在代理对象中的方法把通知[如:MyAdvice 中的 method 方法]内容加进去,就实现了增强,这就是我们所说的代理(Proxy)。
小结
通过这一节中,我们需要掌握的内容有: