手写Spring:第16章-给代理对象的属性设置值

文章目录

  • 一、目标:给代理对象的属性设置值
  • 二、设计:给代理对象的属性设置值
  • 三、实现:给代理对象的属性设置值
    • 3.1 工程结构
    • 3.2 在Bean生命周期中创建代理对象类图
    • 3.3 判断CGLIB对象
    • 3.4 迁移创建AOP代理方法
      • 3.4.1 实例化感知对象处理
      • 3.4.2 扫描自定义注解类
      • 3.4.3 默认自动代理创建者
    • 3.5 在Bean生命周期中初始化执行
  • 四、测试:给代理对象的属性设置值
    • 4.1 添加测试配置
      • 4.1.1 用户服务层实现类
      • 4.1.2 用户前置处理
      • 4.1.3 Spring属性配置文件
    • 4.2 单元测试
  • 五、总结:给代理对象的属性设置值

一、目标:给代理对象的属性设置值

如何给代理对象中的属性填充相应的值?

  • 因为在之前把 AOP 动态代理,融入到 Bean 的生命周期时,创建代理对象是在整个创建 Bean 对象之前,也就是这个代理对象的创建并不是在 Bean 生命周期中。
  • 所以我们要把代理对象的创建融入到 Bean 的生命周期中,也就是需要把创建代理对象的逻辑迁移到 Bean 对象执行初始化方法之后,再执行代理对象的创建。

二、设计:给代理对象的属性设置值

设计:把创建代理对象的逻辑迁移到对象执行初始化之后。

  • 创建代理对象:DefaultAdvisorAutoProxyCreator 实现的 InstantiationAwareBeanPostProcessor 接口。
  • 那么原本在 Before 中的操作,则需要放到 After 中处理

手写Spring:第16章-给代理对象的属性设置值_第1张图片

  • 在创建 Bean 对象 createBean 的生命周期中,有一个阶段是在 Bean 对象属性填充完成以后,执行 Bean 的初始化方法和 BeanPostProcessor 的前置和后置处理。
    • 例如:感知 Aware 对象、处理 init-method 方法等。
  • 那么在这个阶段的 BeanPostProcessor After 就可以用于创建处理对象操作。
  • DefaultAdvisorAutoProxyCreator 用于创建代理对象的操作中,需要把创建操作从 postProcessBeforeInstantiation 方法中迁移到 postProcessAfterInitialization,这样才能满足 Bean 属性填充后的创建操作。

三、实现:给代理对象的属性设置值

3.1 工程结构

spring-step-15
|-src
  |-main
  | |-java
  |   |-com.lino.springframework
  |     |-aop
  |     | |-aspectj
  |     | | |-AspectJExpressionPointcut.java
  |     | | |-AspectJExpressionPointcutAdvisor.java
  |     | |-framework
  |     | | |-adapter
  |     | | | |-MethodBeforeAdviceInterceptor.java
  |     | | |-autoproxy
  |     | | | |-DefaultAdvisorAutoProxyCreator.java
  |     | | |-AopProxy.java
  |     | | |-Cglib2AopProxy.java
  |     | | |-JdkDynamicAopProxy.java
  |     | | |-ProxyFactory.java
  |     | | |-ReflectiveMethodInvocation.java
  |     | |-AdvisedSupport.java
  |     | |-Advisor.java
  |     | |-BeforeAdvice.java
  |     | |-ClassFilter.java
  |     | |-MethodBeforeAdvice.java
  |     | |-MethodMatcher.java
  |     | |-Pointcut.java
  |     | |-PointcutAdvisor.java
  |     | |-TargetSource.java
  |     |-beans
  |     | |-factory
  |     | | |-annotation
  |     | | | |-Autowired.java
  |     | | | |-AutowiredAnnotationBeanPostProcessor.java
  |     | | | |-Qualifier.java
  |     | | | |-Value.java
  |     | | |-config
  |     | | | |-AutowireCapableBeanFactory.java
  |     | | | |-BeanDefinition.java
  |     | | | |-BeanFactoryPostProcessor.java
  |     | | | |-BeanPostProcessor.java
  |     | | | |-BeanReference.java
  |     | | | |-ConfigurableBeanFactory.java
  |     | | | |-InstantiationAwareBeanPostProcessor.java
  |     | | | |-SingletonBeanRegistry.java
  |     | | |-support
  |     | | | |-AbstractAutowireCapableBeanFactory.java
  |     | | | |-AbstractBeabDefinitionReader.java
  |     | | | |-AbstractBeabFactory.java
  |     | | | |-BeabDefinitionReader.java
  |     | | | |-BeanDefinitionRegistry.java
  |     | | | |-CglibSubclassingInstantiationStrategy.java
  |     | | | |-DefaultListableBeanFactory.java
  |     | | | |-DefaultSingletonBeanRegistry.java
  |     | | | |-DisposableBeanAdapter.java
  |     | | | |-FactoryBeanRegistrySupport.java
  |     | | | |-InstantiationStrategy.java
  |     | | | |-SimpleInstantiationStrategy.java
  |     | | |-xml
  |     | | | |-XmlBeanDefinitionReader.java
  |     | | |-Aware.java
  |     | | |-BeanClassLoaderAware.java
  |     | | |-BeanFactory.java
  |     | | |-BeanFactoryAware.java
  |     | | |-BeanNameAware.java
  |     | | |-ConfigurableListableBeanFactory.java
  |     | | |-DisposableBean.java
  |     | | |-FactoryBean.java
  |     | | |-HierarcgicalBeanFactory.java
  |     | | |-InitializingBean.java
  |     | | |-ListableBeanFactory.java
  |     | | |-PropertyPlaceholderConfigurer.java
  |     | |-BeansException.java
  |     | |-PropertyValue.java
  |     | |-PropertyValues.java
  |     |-context
  |     | |-annotation
  |     | | |-ClassPathBeanDefinitionScanner.java
  |     | | |-ClassPathScanningCandidateComponentProvider.java
  |     | | |-Scope.java
  |     | |-event
  |     | | |-AbstractApplicationEventMulticaster.java
  |     | | |-ApplicationContextEvent.java
  |     | | |-ApplicationEventMulticaster.java
  |     | | |-ContextclosedEvent.java
  |     | | |-ContextRefreshedEvent.java
  |     | | |-SimpleApplicationEventMulticaster.java
  |     | |-support
  |     | | |-AbstractApplicationContext.java
  |     | | |-AbstractRefreshableApplicationContext.java
  |     | | |-AbstractXmlApplicationContext.java
  |     | | |-ApplicationContextAwareProcessor.java
  |     | | |-ClassPathXmlApplicationContext.java
  |     | |-ApplicationContext.java
  |     | |-ApplicationContextAware.java
  |     | |-ApplicationEvent.java
  |     | |-ApplicationEventPublisher.java
  |     | |-ApplicationListener.java
  |     | |-ConfigurableApplicationContext.java
  |     |-core.io
  |     | |-ClassPathResource.java
  |     | |-DefaultResourceLoader.java
  |     | |-FileSystemResource.java
  |     | |-Resource.java
  |     | |-ResourceLoader.java
  |     | |-UrlResource.java
  |     |-stereotype
  |     | |-Component.java
  |     |-util
  |     | |-ClassUtils.java
  |     | |-StringValueResolver.java
  |-test
    |-java
      |-com.lino.springframework.test
                |-bean
                | |-IUserService.java
                | |-UserService.java
        | |-UserServiceBeforeAdvice.java
                |-ApiTest.java
    |-resources
      |-spring.xml
      |-token.properties

3.2 在Bean生命周期中创建代理对象类图

手写Spring:第16章-给代理对象的属性设置值_第2张图片

  • 本节完成关于代理对象中属性的填充问题,但实际解决的思路是处理在 Bean 生命周期中合适的位置(初始化 initializeBean)中处理代理类的创建。
  • 主要包括:
    • DefaultAdvisorAutoProxyCreator 类创建代理对象的操作放置在 postProcessAfterInitialization 方法中。
    • AbstractAutowireCapableBeanFactory 完成初始化方法的调用操作。
  • 注意:在目前的 Spring 框架中,AbstractAutowireCapableBeanFactory 类里使用的是 CglibSubclassingInstantiationStrategy 创建对象,所有有需要判断对象获取接口的方法中,也都需要判断是否为 CGLIB 创建,否则是不能正确获取到接口的。
    • 如:ClassUtils.isCglibProxyClass(clazz) ? clazz.getSuperclass() : clazz

3.3 判断CGLIB对象

TargetSource.java

package com.lino.springframework.aop;

import com.lino.springframework.util.ClassUtils;

/**
 * @description: 被代理的目标对象
 */
public class TargetSource {

    private final Object target;

    public TargetSource(Object target) {
        this.target = target;
    }

    /**
     * 获取目标对象列表
     *
     * @return 目标对象列表
     */
    public Class<?>[] getTargetClass() {
        Class<?> clazz = this.target.getClass();
        clazz = ClassUtils.isCglibProxyClass(clazz) ? clazz.getSuperclass() : clazz;
        return clazz.getInterfaces();
    }

    /**
     * 获取目标对象
     *
     * @return 目标对象
     */
    public Object getTarget() {
        return this.target;
    }
}
  • TargetSource#getTargetClass 是用于获取 target 对象的接口信息的,那么这个 target 可以是 JDK 代理创建,也可能是 CGLIB 创建。
  • 为了保证都能正确的获取到结果,这里需要增加判断 ClassUtils.isCglibProxyClass(clazz)

3.4 迁移创建AOP代理方法

3.4.1 实例化感知对象处理

InstantiationAwareBeanPostProcessor.java

package com.lino.springframework.beans.factory.config;

import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.PropertyValues;

/**
 * @description: 实例化感知对象处理
 */
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {

    /**
     * 在 Bean 对象执行初始化方法之前,执行此方法
     *
     * @param beanClass 对象类
     * @param beanName  对象名
     * @return 新对象
     * @throws BeansException 异常
     */
    Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException;

    /**
     * 在 Bean 对象执行初始化方法之后,执行此方法
     *
     * @param bean     对象
     * @param beanName 对象名称
     * @return 是否执行
     * @throws BeansException 异常
     */
    boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException;

    /**
     * 在 Bean 对象实例化完成后,设置属性操作之前执行此方法
     *
     * @param pvs      属性值集合
     * @param bean     对象
     * @param beanName 对象名称
     * @return 属性值集合
     * @throws BeansException 异常
     */
    PropertyValues postProcessPropertyValues(PropertyValues pvs, Object bean, String beanName) throws BeansException;
}

3.4.2 扫描自定义注解类

AutowiredAnnotationBeanPostProcessor.java

package com.lino.springframework.beans.factory.annotation;

import cn.hutool.core.bean.BeanUtil;
import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.PropertyValues;
import com.lino.springframework.beans.factory.BeanFactory;
import com.lino.springframework.beans.factory.BeanFactoryAware;
import com.lino.springframework.beans.factory.config.ConfigurableBeanFactory;
import com.lino.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import com.lino.springframework.util.ClassUtils;
import java.lang.reflect.Field;

/**
 * @description: 扫描自定义注解类
 */
public class AutowiredAnnotationBeanPostProcessor implements InstantiationAwareBeanPostProcessor, BeanFactoryAware {

    ...

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return null;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return null;
    }

    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        return null;
    }

    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        return true;
    }
}

3.4.3 默认自动代理创建者

DefaultAdvisorAutoProxyCreator.java

package com.lino.springframework.aop.framework.autoproxy;

import com.lino.springframework.aop.*;
import com.lino.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor;
import com.lino.springframework.aop.framework.ProxyFactory;
import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.PropertyValues;
import com.lino.springframework.beans.factory.BeanFactory;
import com.lino.springframework.beans.factory.BeanFactoryAware;
import com.lino.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import com.lino.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInterceptor;
import java.util.Collection;

/**
 * @description: 默认自动代理创建者
 */
public class DefaultAdvisorAutoProxyCreator implements InstantiationAwareBeanPostProcessor, BeanFactoryAware {

    private DefaultListableBeanFactory beanFactory;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = (DefaultListableBeanFactory) beanFactory;
    }

    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        return null;
    }

    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        return true;
    }

    private boolean isInfrastructureClass(Class<?> beanClass) {
        return Advice.class.isAssignableFrom(beanClass) || Pointcut.class.isAssignableFrom(beanClass) || Advisor.class.isAssignableFrom(beanClass);
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (isInfrastructureClass(bean.getClass())) {
            return bean;
        }

        Collection<AspectJExpressionPointcutAdvisor> advisors = beanFactory.getBeansOfType(AspectJExpressionPointcutAdvisor.class).values();

        for (AspectJExpressionPointcutAdvisor advisor : advisors) {
            ClassFilter classFilter = advisor.getPointcut().getClassFilter();
            // 过滤匹配类
            if (!classFilter.matches(bean.getClass())) {
                continue;
            }
            AdvisedSupport advisedSupport = new AdvisedSupport();

            TargetSource targetSource = new TargetSource(bean);
            advisedSupport.setTargetSource(targetSource);
            advisedSupport.setMethodInterceptor((MethodInterceptor) advisor.getAdvice());
            advisedSupport.setMethodMatcher(advisor.getPointcut().getMethodMatcher());
            advisedSupport.setProxyTargetClass(false);

            // 返回代理对象
            return new ProxyFactory(advisedSupport).getProxy();
        }
        return bean;
    }

    @Override
    public PropertyValues postProcessPropertyValues(PropertyValues pvs, Object bean, String beanName) throws BeansException {
        return pvs;
    }
}
  • 关于 DefaultAdvisorAutoProxyCreator 类的操作主要就是把创建 AOP 代理的操作从 postProcessBeforeInstantiation 移动到 postProcessAfterInitialization 中。
  • 通过设置一些 AOP 的必备参数后,返回代理对象 new ProxyFactory(advisedSupport).getProxy()
    • 这个代理对象中就包括间接调用 TargetSource#getTargetClass 的获取。

3.5 在Bean生命周期中初始化执行

AbstractAutowireCapableBeanFactory.java

package com.lino.springframework.beans.factory.support;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.PropertyValue;
import com.lino.springframework.beans.PropertyValues;
import com.lino.springframework.beans.factory.*;
import com.lino.springframework.beans.factory.config.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

/**
 * @description: 实现默认bean创建的抽象bean工厂超类
 * @author: lingjian
 * @createDate: 2022/11/22 14:39
 */
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {

    private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();

    @Override
    protected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) {
        Object bean = null;
        try {
            // 判断是否返回代理 Bean 对象
            bean = resolveBeforeInstantiation(beanName, beanDefinition);
            if (null != bean) {
                return bean;
            }
            // 实例化Bean
            bean = createBeanInstance(beanDefinition, beanName, args);
            // 实例化后判断
            boolean continueWithPropertyPopulation = applyBeanPostProcessorsAfterInstantiation(beanName, bean);
            if (!continueWithPropertyPopulation) {
                return bean;
            }
            // 在设置Bean属性之前,允许 BeanPostProcessor修改属性值
            applyBeanPostProcessorsBeforeApplyingPropertyValues(beanName, bean, beanDefinition);
            // 给bean填充属性
            applyPropertyValues(beanName, bean, beanDefinition);
            // 执行 Bean 的初始化方法和 BeanPostProcessor 的前置和后置处理方法
            bean = initializeBean(beanName, bean, beanDefinition);
        } catch (Exception e) {
            throw new BeansException("Instantiation of bean failed", e);
        }

        // 注册实现 DisposableBean 接口的 Bean 对象
        registerDisposableBeanIfNecessary(beanName, bean, beanDefinition);

        // 判断 SCOPE_SINGLETON、SCOPE_PROTOTYPE
        if (beanDefinition.isSingleton()) {
            registerSingletonBean(beanName, bean);
        }
        return bean;
    }

    /**
     * Bean 实例化后对于返回 false 的对象,不再执行后续设置 Bean 对象属性的操作
     *
     * @param beanName 对象名称
     * @param bean     对象
     * @return 布尔值
     */
    private boolean applyBeanPostProcessorsAfterInstantiation(String beanName, Object bean) {
        boolean continueWithPropertyPopulation = true;
        for (BeanPostProcessor beanPostProcessor : getBeanPostProcessors()) {
            if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
                InstantiationAwareBeanPostProcessor instantiationAwareBeanPostProcessor = (InstantiationAwareBeanPostProcessor) beanPostProcessor;
                if (!instantiationAwareBeanPostProcessor.postProcessAfterInstantiation(bean, beanName)) {
                    continueWithPropertyPopulation = false;
                    break;
                }
            }
        }
        return continueWithPropertyPopulation;
    }

    ...

    private Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
        for (BeanPostProcessor beanPostProcessor : getBeanPostProcessors()) {
            if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
                Object result = ((InstantiationAwareBeanPostProcessor) beanPostProcessor).postProcessBeforeInstantiation(beanClass, beanName);
                if (null != result) {
                    return result;
                }
            }
        }
        return null;
    }

    ...
}
  • AbstractAutowireCapableBeanFactory#createBean 方法中,关注点在于 initializeBean -> applyBeanPostProcessorsAfterInitialization 这块逻辑的调用,最终完成 AOP 代理对象的创建操作。

四、测试:给代理对象的属性设置值

4.1 添加测试配置

4.1.1 用户服务层实现类

UserService.java

package com.lino.springframework.test.bean;

import com.lino.springframework.beans.factory.annotation.Autowired;
import com.lino.springframework.beans.factory.annotation.Value;
import com.lino.springframework.stereotype.Component;
import java.util.Random;

/**
 * @description: 用户接口实现类
 */
public class UserService implements IUserService {

    private String token;

    @Override
    public String queryUserInfo() {
        try {
            Thread.sleep(new Random(1).nextInt(100));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "张三,10001,杭州," + token;
    }

    @Override
    public String register(String userName) {
        try {
            Thread.sleep(new Random(1).nextInt(100));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "注册用户:" + userName + " success!";
    }

    @Override
    public String toString() {
        return "UserService#token = {" + token + "}";
    }

    public String getToken() {
        return token;
    }

    public void setToken(String token) {
        this.token = token;
    }
}

4.1.2 用户前置处理

UserServiceBeforeAdvice.java

package com.lino.springframework.test.bean;

import com.lino.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;

/**
 * @description: 用户前置处理
 */
public class UserServiceBeforeAdvice implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("拦截方法:" + method.getName());
    }
}

4.1.3 Spring属性配置文件

spring.xml


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
	         http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="userService" class="com.lino.springframework.test.bean.UserService">
        <property name="token" value="RejDlI78hu223Opo983Ds"/>
    bean>

    <bean class="com.lino.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>

    <bean id="beforeAdvice" class="com.lino.springframework.test.bean.UserServiceBeforeAdvice"/>

    <bean id="methodInterceptor" class="com.lino.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor">
        <property name="advice" ref="beforeAdvice"/>
    bean>

    <bean id="pointcutAdvisor" class="com.lino.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor">
        <property name="expression" value="execution(* com.lino.springframework.test.bean.IUserService.*(..))"/>
        <property name="advice" ref="methodInterceptor"/>
    bean>

beans>

4.2 单元测试

ApiTest.java

@Test
public void test_autoProxy() {
    ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml");
    IUserService userService = applicationContext.getBean("userService", IUserService.class);
    System.out.println("测试结果:" + userService.queryUserInfo());
}

测试结果

拦截方法:queryUserInfo
测试结果:张三,10001,杭州,RejDlI78hu223Opo983Ds

手写Spring:第16章-给代理对象的属性设置值_第3张图片

  • 测试结果看,通过对 Bean 生命周期的调整,在创建 AOP 代理对象就可以把代理对象的属性信息填充进去了。

五、总结:给代理对象的属性设置值

  • 核心内容主要是完善 Bean 的生命周期,在创建类的操作中完成代理对象的创建。
    • 通过这样的方式就可以让代理对象中的属性也可以随着创建过程被填充进行。
  • 除核心功能的实现外,也要关注到对象的初始化操作:CglibSubclassingInstantiationStrategySimpleInstantiationStrategy
    • 这两种方式中 CGLIB 创建对象,会影响到很多地方用于接口获取的操作。因为 CGLIB 创建对象走的是 ASM 字节码生成的操作,所以和普通的 JDK 代理生成对象是不一样,需要注意。

你可能感兴趣的:(手写spring,spring,java)