《Spring技术内幕》笔记-第三章 Spring AOP的实现

本文深入探讨了Spring AOP(面向切面编程)的核心概念和技术细节,包括AOP的基本原理、关键组件如Advice、Pointcut和Advisor的作用及其实现方式。此外,还详细分析了Spring如何利用JDK动态代理和CGLIB生成代理对象,以及ProxyFactoryBean的配置和使用方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

AOP 概述

   1, AOP:Aspect-Oriented Programming:一种模块化机制,用来描述分散在对象,类或方法中的横切关注点。从关注点中分离出横切关注点是面向切面编程的核心概念。分离关注点使解决特定领域的代码从业务逻辑中独立出来,业务逻辑代码不再有对特定领域代码的调用。特定领域的问题通过切面封装,维护,这样子分散在整个应用程序的变动就可以很好的管理。

   2, Adivice通知

    Advice定义连接点做什么,为切面增强提供织入接口。在Spring AOP中,主要描述Spring AOP围绕方法调用而注入的切面行为。

    Spring提供了更具体的通知类型,比如BeforeAdvice,AfterAdvice等。

    下面以BeforeAdvice为例:

    BeforeAdvice是一个标记接口(marker interface).

 
  1. public interface BeforeAdvice extends Advice {

  2. }

具体我们看MethodBeforeAdvice接口。

 
  1. public interface MethodBeforeAdvice extends BeforeAdvice {

  2. void before(Method method, Object[] args, Object target) throws Throwable;

  3. }

具体参数:method:目标方法的反射对象。args:方法执行参数。target:方法执行的对象。以CountingBeforeAdvice为例,该类完成统计被调用方法的次数。

 
  1. public class CountingBeforeAdvie implements MethodBeforeAdvice{

  2. public void before(Method method, Object[] args, Object target) throws Throwable{

  3. count(method);

  4. }

  5. }

count方法通过hashMap存储Method对象和调用次数。

 2,Pointcut切点

    Pointcut切点决定Advice通知作用于哪个连接点,就是说通过Pointcut来定义需要增强的方法集合。

    Spring以Pointcut接口为中心,实现了一系列的类。


3,Advisor通知器

    Advisor通知器定义在哪个切点Pointcut使用哪个Advice。

    以Advisor的实现DefaultPointcutAdvisor为例。在DefaultPointcutAdvisor中,有两个成员变量,分别是pointCut和Advice。

  
  1. public class DefaultPointcutAdvisor extends AbstractGenericPointcutAdvisor implements Serializable
成员变量和构造方法。
  
  1. private Pointcut pointcut = Pointcut.TRUE;
  2. public DefaultPointcutAdvisor(Pointcut pointcut, Advice advice) {
  3. this.pointcut = pointcut;
  4. setAdvice(advice);
  5. }
   
  1. public interface Pointcut {
  2. /**
  3. * Return the ClassFilter for this pointcut.
  4. * @return the ClassFilter (never {@code null})
  5. */
  6. ClassFilter getClassFilter();
  7. /**
  8. * Return the MethodMatcher for this pointcut.
  9. * @return the MethodMatcher (never {@code null})
  10. */
  11. MethodMatcher getMethodMatcher();
  12. /**
  13. * Canonical Pointcut instance that always matches.
  14. */
  15. Pointcut TRUE = TruePointcut.INSTANCE;
  16. }

我们看到Pointcut引用的TRUE成员。这里使用的是单例(singleton,书中称为单件,感觉比较奇怪)。

查看TruePointcut

   
  1. class TruePointcut implements Pointcut, Serializable {
  2. public static final TruePointcut INSTANCE = new TruePointcut();
  3. /**
  4. * Enforce Singleton pattern.
  5. */
  6. private TruePointcut() {
  7. }
  8. @Override
  9. public ClassFilter getClassFilter() {
  10. return ClassFilter.TRUE;
  11. }
  12. @Override
  13. public MethodMatcher getMethodMatcher() {
  14. return MethodMatcher.TRUE;
  15. }
  16. /**
  17. * Required to support serialization. Replaces with canonical
  18. * instance on deserialization, protecting Singleton pattern.
  19. * Alternative to overriding {@code equals()}.
  20. */
  21. private Object readResolve() {
  22. return INSTANCE;
  23. }
  24. @Override
  25. public String toString() {
  26. return "Pointcut.TRUE";
  27. }
  28. }
Spring AOP的设计与实现

1,JVM的动态代理特性
    JVM的动态代理有关可以参考:http://blog.csdn.net/mergades/article/details/42173893

2,Spring AOP的设计

    Spring AOP的设计核心即使动态代理模式。

3,配置ProxyFactoryBean

    ProxyFactoryBean是在Spring IoC环境中创建AOP应用的底层方法,Spring通过该类完成了对AOP使用的封装。ProxyFactoryBean的配置和使用如下:

    -1,定义使用的通知器Advisor,这个通知器通过Bean定义,并实现了对应的切面行为。

    -2,定义ProxyFactoryBean,把它作为另一个Bean来定义,它使封装AOP功能的主要类。

    -3,定义target属性。

4,ProxyFactoryBean生成AOPProxy对象。

    在Spring中可以同各国ProxyFactoryBean来完成对AOP的配置目标对象和切面行为。我们可以查看其对应的属性:

  
  1. public class ProxyFactoryBean extends ProxyCreatorSupport
  2. implements FactoryBean<Object>, BeanClassLoaderAware, BeanFactoryAware {
  3. /**
  4. * This suffix in a value in an interceptor list indicates to expand globals.
  5. */
  6. public static final String GLOBAL_SUFFIX = "*";
  7. protected final Log logger = LogFactory.getLog(getClass());
  8. private String[] interceptorNames;//已经定好的通知器
  9. private String targetName;//目标对象
  10. private boolean autodetectInterfaces = true;
  11. private boolean singleton = true;
  12. private AdvisorAdapterRegistry advisorAdapterRegistry = GlobalAdvisorAdapterRegistry.getInstance();
  13. private boolean freezeProxy = false;
  14. private transient ClassLoader proxyClassLoader = ClassUtils.getDefaultClassLoader();
  15. private transient boolean classLoaderConfigured = false;
  16. private transient BeanFactory beanFactory;
  17. /** Whether the advisor chain has already been initialized */
  18. private boolean advisorChainInitialized = false;
  19. /** If this is a singleton, the cached singleton proxy instance */
  20. private Object singletonInstance;

ProxyFactoryBean依赖JDK的动态代理或者CGLIB提供的PROXY属性。

 在该类中,getObject()方法对通知链进行初始化。并对Singleton和prototype类型的对象做出区分。

  
  1. public Object getObject() throws BeansException {
  2. initializeAdvisorChain();
  3. if (isSingleton()) {
  4. return getSingletonInstance();
  5. }
  6. else {
  7. if (this.targetName == null) {
  8. logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
  9. "Enable prototype proxies by setting the 'targetName' property.");
  10. }
  11. return newPrototypeInstance();
  12. }
  13. }

initializeAdvisorChain()方法:

  
  1. private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
  2. if (this.advisorChainInitialized) {
  3. return;//如果已经初始化,则直接返回。
  4. }
  5. if (!ObjectUtils.isEmpty(this.interceptorNames)) {
  6. if (this.beanFactory == null) {
  7. throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +
  8. "- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));
  9. }
  10. // Globals can't be last unless we specified a targetSource using the property...
  11. if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) &&
  12. this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {
  13. throw new AopConfigException("Target required after globals");
  14. }
  15. // Materialize interceptor chain from bean names.

  16. //根据配置,添加调用

  17. for (String name : this.interceptorNames) {
  18. if (logger.isTraceEnabled()) {
  19. logger.trace("Configuring advisor or advice '" + name + "'");
  20. }
  21. if (name.endsWith(GLOBAL_SUFFIX)) {
  22. if (!(this.beanFactory instanceof ListableBeanFactory)) {
  23. throw new AopConfigException(
  24. "Can only use global advisors or interceptors with a ListableBeanFactory");
  25. }
  26. addGlobalAdvisor((ListableBeanFactory) this.beanFactory,
  27. name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
  28. }
  29. else {
  30. // If we get here, we need to add a named interceptor.
  31. // We must check if it's a singleton or prototype.
  32. Object advice;
  33. if (this.singleton || this.beanFactory.isSingleton(name)) {
  34. // Add the real Advisor/Advice to the chain.
  35. advice = this.beanFactory.getBean(name);
  36. }
  37. else {
  38. // It's a prototype Advice or Advisor: replace with a prototype.
  39. // Avoid unnecessary creation of prototype bean just for advisor chain initialization.
  40. advice = new PrototypePlaceholderAdvisor(name);
  41. }
  42. addAdvisorOnChainCreation(advice, name);
  43. }
  44. }
  45. }
  46. this.advisorChainInitialized = true;
  47. }

Spring再通过该类的getSingletonInstance()方法生成对应单例的代理对象。

  
  1. private synchronized Object getSingletonInstance() {
  2. if (this.singletonInstance == null) {
  3. this.targetSource = freshTargetSource();
  4. if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
  5. // Rely on AOP infrastructure to tell us what interfaces to proxy.
  6. Class<?> targetClass = getTargetClass();
  7. if (targetClass == null) {
  8. throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");
  9. }
  10. setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
  11. }
  12. // Initialize the shared singleton instance.
  13. super.setFrozen(this.freezeProxy);
  14. this.singletonInstance = getProxy(createAopProxy());
  15. }
  16. return this.singletonInstance;
  17. }

getProxy()方法:

  
  1. protected Object getProxy(AopProxy aopProxy) {
  2. return aopProxy.getProxy(this.proxyClassLoader);
  3. }
Spring通过AopProxy接口把AOP代理对象的实现与框架有效地分开。

在getSingletonInstance()方法中,我们可以继续查看createAopProxy()方法,在该方法中:

  
  1. protected final synchronized AopProxy createAopProxy() {
  2. if (!this.active) {
  3. activate();
  4. }
  5. return getAopProxyFactory().createAopProxy(this);
  6. }

在ProxyCreatorSupport中,可以看到具体的代理生成,通过AopProxyFactory实现。

  
  1. protected final synchronized AopProxy createAopProxy() {
  2. if (!this.active) {
  3. activate();
  4. }
  5. return getAopProxyFactory().createAopProxy(this);
  6. }
构造方法:

  
  1. public ProxyCreatorSupport() {
  2. this.aopProxyFactory = new DefaultAopProxyFactory();
  3. }

在AopProxy代理对象的生成时,如果目标是接口类,那么适合使用JDK来生成代理对象,否砸Spring会事项CGLIB来生成目标对象的代理对象。在此类中,具体不同的代理对象的具体生成使用不同的策略JdkDynamicAopProxy和CglibProxyFactory生成,只是DefaultAopProxyFactory对其进行了调用。

    

  
  1. public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
  2. if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
  3. Class<?> targetClass = config.getTargetClass();
  4. if (targetClass == null) {
  5. throw new AopConfigException("TargetSource cannot determine target class: " +
  6. "Either an interface or a target is required for proxy creation.");
  7. }
  8. if (targetClass.isInterface()) {//接口类
  9. return new JdkDynamicAopProxy(config);
  10. }
  11. return new ObjenesisCglibAopProxy(config);
  12. }
  13. else {
  14. return new JdkDynamicAopProxy(config);
  15. }
  16. }
5,JDK生成AopProxy代理对象

JDk通过JdkDynamicAopProxy类实现生成代理对象,该类实现了AopProxy接口。

getProxy()方法完全是基于JDK原生的动态代理来实现的。

  
  1. @Override
  2. public Object getProxy() {
  3. return getProxy(ClassUtils.getDefaultClassLoader());
  4. }
  5. @Override
  6. public Object getProxy(ClassLoader classLoader) {
  7. if (logger.isDebugEnabled()) {
  8. logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
  9. }
  10. Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
  11. findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
  12. return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
  13. }

6,CGLIB生成AopProxy对象。

    在Spring 4 中,已经实现ObjenesisCglibAopProxy来生成代理对象,与书中代码不同。该类实现了CglibAopProxy,我们查看其对应的getProxy方法:

  
  1. @Override
  2. public Object getProxy(ClassLoader classLoader) {
  3. if (logger.isDebugEnabled()) {
  4. logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource());
  5. }
  6. try {//advised中获取target对象
  7. Class<?> rootClass = this.advised.getTargetClass();
  8. Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");
  9. Class<?> proxySuperClass = rootClass;
  10. if (ClassUtils.isCglibProxyClass(rootClass)) {
  11. proxySuperClass = rootClass.getSuperclass();
  12. Class<?>[] additionalInterfaces = rootClass.getInterfaces();
  13. for (Class<?> additionalInterface : additionalInterfaces) {
  14. this.advised.addInterface(additionalInterface);
  15. }
  16. }
  17. // Validate the class, writing log messages as necessary.
  18. validateClassIfNecessary(proxySuperClass);
  19. // Configure CGLIB Enhancer...
  20. Enhancer enhancer = createEnhancer();
  21. if (classLoader != null) {
  22. enhancer.setClassLoader(classLoader);
  23. if (classLoader instanceof SmartClassLoader &&
  24. ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
  25. enhancer.setUseCache(false);
  26. }
  27. }
  28. enhancer.setSuperclass(proxySuperClass);
  29. enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
  30. enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
  31. enhancer.setStrategy(new UndeclaredThrowableStrategy(UndeclaredThrowableException.class));
  32. Callback[] callbacks = getCallbacks(rootClass);
  33. Class<?>[] types = new Class<?>[callbacks.length];
  34. for (int x = 0; x < types.length; x++) {
  35. types[x] = callbacks[x].getClass();
  36. }
  37. // fixedInterceptorMap only populated at this point, after getCallbacks call above
  38. enhancer.setCallbackFilter(new ProxyCallbackFilter(
  39. this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
  40. enhancer.setCallbackTypes(types);
  41. // Generate the proxy class and create a proxy instance.
  42. return createProxyClassAndInstance(enhancer, callbacks);
  43. }
  44. catch (CodeGenerationException ex) {
  45. throw new AopConfigException("Could not generate CGLIB subclass of class [" +
  46. this.advised.getTargetClass() + "]: " +
  47. "Common causes of this problem include using a final class or a non-visible class",
  48. ex);
  49. }
  50. catch (IllegalArgumentException ex) {
  51. throw new AopConfigException("Could not generate CGLIB subclass of class [" +
  52. this.advised.getTargetClass() + "]: " +
  53. "Common causes of this problem include using a final class or a non-visible class",
  54. ex);
  55. }
  56. catch (Exception ex) {
  57. // TargetSource.getTarget() failed
  58. throw new AopConfigException("Unexpected AOP exception", ex);
  59. }
  60. }




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值