模仿Autowired生成一个自定义接口代理对象的后处理器

1.编写代理类

package com.cx.test.demo.spring.proxy;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
import org.springframework.context.ApplicationContext;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * 代理类
 *
 * @date 2021-09-26
 * @see CoreFacadeBeanPostProcessor
 */
public class CoreFacadeProxy<T> implements InvocationHandler {
    
    

    public static final String METHOD_EQUALS = "equals";

    /**
     * 被代理的接口
     */
    private Class<T> interfaceClass;

    /**
     * 上下文
     */
    private ApplicationContext applicationContext;

    public CoreFacadeProxy(Class<T> interfaceClass, ApplicationContext applicationContext) {
    
    
        this.interfaceClass = interfaceClass;
        this.applicationContext = applicationContext;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
        String methodName = method.getName();
        //调用CoreFacadeProxy的equals方法 此时args[0]就是要比较的参数 这个是对object的方法进行处理
        if (METHOD_EQUALS.equals(methodName)) {
    
    
            //自定义比较方法
            return this.equals(args[0]);
        }
         //所以方法都动态代理
        if ("hashCode".equals(methodName)) {
    
    
            return this.hashCode();
        }
        if ("toString".equals(methodName)) {
    
    
            return this.toString();
        }

        T impl = this.getImpl(applicationContext, interfaceClass, args);
        return method.invoke(impl, args);
    }

    /**
     * 获取实现类
     *
     * @param applicationContext 上下文
     * @param interfaceClass     接口
     * @param args               入参
     * @return
     */
    private T getImpl(ApplicationContext applicationContext, Class<T> interfaceClass, Object[] args) {
    
    
        if (ArrayUtils.isEmpty(args)) {
    
    
//            LoggerUtils.ERROR.error("params must not be empty");
            throw new IllegalArgumentException("params must not be empty");
        }

        Object channel = args[0];
        if (!(channel instanceof Integer)) {
    
    
            String message = "first param must be TaxiChannelCode, found: " + (Objects.isNull(channel) ? "null" : String.valueOf(channel));
//            LoggerUtils.ERROR.error(message);
            throw new IllegalArgumentException(message);
        }

        Map<String, T> map = applicationContext.getBeansOfType(interfaceClass);
        if (MapUtils.isEmpty(map)) {
    
    
            NoSuchBeanDefinitionException ex = new NoSuchBeanDefinitionException(interfaceClass.getSimpleName());
//            LoggerUtils.ERROR.error("impl not found", ex);
            throw ex;
        }

        List<T> implList = map.values().stream()
                .filter(Objects::nonNull)
                .filter(this::notProxy)
                .filter(e -> channel.equals(((Supplier) e).get()))
                .collect(Collectors.toList());

        if (CollectionUtils.isEmpty(implList)) {
    
    
            NoSuchBeanDefinitionException ex = new NoSuchBeanDefinitionException(interfaceClass.getSimpleName(), ((Integer) channel).toString());
//            LoggerUtils.ERROR.error("impl not found", ex);
            throw ex;
        } else if (implList.size() > 1) {
    
    
            NoUniqueBeanDefinitionException ex = new NoUniqueBeanDefinitionException(interfaceClass,
                    implList.stream().map(e -> e.getClass().getName()).collect(Collectors.toList()));
//            LoggerUtils.ERROR.error("more then one impl", ex);
            throw ex;
        }

        return implList.get(0);
    }

    private boolean notProxy(T e) {
    
    
        return !(e instanceof Proxy);
    }

    @Override
    public boolean equals(Object o) {
    
    
        if (this == o) {
    
    
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
    
    
            return false;
        }
        CoreFacadeProxy<?> that = (CoreFacadeProxy<?>) o;
        return interfaceClass.equals(that.interfaceClass);
    }

    @Override
    public int hashCode() {
    
    
        return Objects.hash(interfaceClass);
    }
    
    @Override
    public String toString() {
    
    
        return interfaceClass.getName()+ "@" + Integer.toHexString(hashCode());
    }
}

2.编写后处理器

package com.cx.test.demo.spring.proxy;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.beans.factory.annotation.InjectionMetadata;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.BridgeMethodResolver;
import org.springframework.core.Ordered;
import org.springframework.core.PriorityOrdered;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;

import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import static org.springframework.core.annotation.AnnotationUtils.getAnnotation;

/**
 * 生成代理并注入
 * 有Autowired注解并且在BASE_PACKAGES包下的接口
 * TODO ElementType.CONSTRUCTOR ElementType.PARAMETER
 *
 * @author cx
 * @date 2021-09-29
 * @see Autowired
 * @see CoreFacadeProxy
 */
@Component
public class CoreFacadeBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter
        implements ApplicationContextAware, MergedBeanDefinitionPostProcessor, PriorityOrdered {
    
    

    private final Log logger = LogFactory.getLog(getClass());
	//也可以判断是否对应接口是否继承某个接口
    //private static final Class INTERFACE = CoreFacade.class;
    private static final String BASE_PACKAGES = "com.cx.test.demo.spring.service";

    private static final Class<? extends Annotation> ANNOTATION = Autowired.class;
    //优先级要大于@Autowired 不然Autowired就无法去装载接口多个实现类
    private int order = Ordered.LOWEST_PRECEDENCE - 3;
    /**
     *     findAnnotationMetadata 遍历两遍 第一遍缓存的class 后面就无需在进行遍历验证
     * @see CoreFacadeBeanPostProcessor#findAnnotationMetadata(java.lang.String, java.lang.Class, org.springframework.beans.PropertyValues)
     */
    private final Map<String, InjectionMetadata> injectionMetadataCache = new ConcurrentHashMap<>(256);
    /**
     * 注入实例缓存
     */
    private final ConcurrentMap<String, Object> injectedObjectsCache = new ConcurrentHashMap<String, Object>(16);

    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    
    
        this.applicationContext = applicationContext;
    }

    /**
     * 优先于InstantiationAwareBeanPostProcessorAdapter 此时Spring bean还未实例 还未初始化
     * 此时可以对beanDefinition进行处理
     
     * 此处是检查并注册要注入 类的方法属性(member)信息到该类beanDefinition配置信息当中
     * 模仿 AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition
     * @param beanDefinition
     * @param beanType
     * @param beanName
     * @see AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition(org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Class, java.lang.String)
     */
    @Override
    public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
    
    
        //找到有Autowired注解并且在BASE_PACKAGES包下的接口符合的InjectionMetadata元数据
        InjectionMetadata metadata = findAnnotationMetadata(beanName, beanType, null);
		
        //检查并注册要注入 member(element子)信息到beanName对应的beanDefinition配置信息当中 
        //beanDefinition.registerExternallyManagedConfigMember(member);
       metadata.checkConfigMembers(beanDefinition);
    }

    /**
     * postProcessPropertyValues 所有实例生成还未初始化时对bean进行处理
     * 此时是执行注入metadata 对应类的checkedElements(就是我们自定义修改的属性或者方法参数 可以理解就是赋值)

     * @param pvs
     * @param pds
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
    
    
        InjectionMetadata metadata = findAnnotationMetadata(beanName, bean.getClass(), pvs);
        try {
    
    
            //对bean的元数据(属性,方法)进行处理,
            // InjectionMetadata中本质是去遍历InjectionMetadata.InjectedElement 去执行自定义的element.inject(target, beanName, pvs);
            metadata.inject(bean, beanName, pvs);
        } catch (BeanCreationException ex) {
    
    
            throw ex;
        } catch (Throwable ex) {
    
    
            throw new BeanCreationException(beanName, "Injection of Autowired dependencies failed", ex);
        }
        return pvs;
    }

    /**
     * 获取当前类的优先级
     * @return
     */
    @Override
    public int getOrder() {
    
    
        return this.order;
    }

    public void setOrder(int order) {
    
    
        this.order = order;
    }

    /**
     * 此处模仿 AutowiredAnnotationBeanPostProcessor#findAutowiringMetadata
     * 最主要的是 metadata = buildAnnotationMetadata(clazz); 我们去去定义自己处理field和method的element
     * @param beanName
     * @param clazz
     * @param pvs
     * @return
     * @see AutowiredAnnotationBeanPostProcessor#findAutowiringMetadata(java.lang.String, java.lang.Class, org.springframework.beans.PropertyValues)
     */
    private InjectionMetadata findAnnotationMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
    
    
        // Fall back to class name as cache key, for backwards compatibility with custom callers.
        String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
        // Quick check on the concurrent map first, with minimal locking.
        InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
        //postProcessMergedBeanDefinition 缓存存在就不需要刷新了, postProcessPropertyValues处理时就不会再去执行buildAnnotationMetadata,
        //只会处理后续postProcessMergedBeanDefinition 完成后的新的元数据 后续生成的InjectionMetadata
        if (InjectionMetadata.needsRefresh(metadata, clazz)) {
    
    
            synchronized (this.injectionMetadataCache) {
    
    
                metadata = this.injectionMetadataCache.get(cacheKey);
                if (InjectionMetadata.needsRefresh(metadata, clazz)) {
    
    
                    if (metadata != null) {
    
    
                      //查看源码 发现该方法是将其pvs属性标示为未处理的
                        metadata.clear(pvs);
                    }
                    //我们可以在此处去定义自己处理field和method的element
                    metadata = buildAnnotationMetadata(clazz);
                    //缓存
                    this.injectionMetadataCache.put(cacheKey, metadata);
                }
            }
        }
        return metadata;
    }

    /**
     * 自定义完成之后 postProcessPropertyValues中 会执行 FieldInjectedElement 回调实体 inject 方法 对inject进行处理
     * InjectionMetadata#inject 会对类的元信息进行处理
     * @see InjectionMetadata#inject(java.lang.Object, java.lang.String, org.springframework.beans.PropertyValues)
     * @param clazz
     * @return
     */
    private InjectionMetadata buildAnnotationMetadata(final Class<?> clazz) {
    
    
        //Element 我们可以在此处对自己想修改的类的方法和属性 生成一个自定义操作的InjectedElement 进行处理
        final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
        //遍历clazz的 操作field
        ReflectionUtils.doWithLocalFields(clazz, field -> {
    
    
            if (isTarget(field)) {
    
    
                //校验是否为静态
                if (Modifier.isStatic(field.getModifiers())) {
    
    
                    if (logger.isWarnEnabled()) {
    
    
                        logger.warn("Autowired annotation is not supported on static fields: " + field);
                    }
                    return;
                }
                // postProcessPropertyValues中 会执行 FieldInjectedElement 回调实体 inject 方法 对inject进行处理
                //field自定义属性
                currElements.add(new FieldInjectedElement(field));
            }
        });
        //判断method
        ReflectionUtils.doWithLocalMethods(clazz, method -> {
    
    
            Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
            if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
    
    
                return;
            }

            if (isTarget(bridgedMethod) && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
    
    
                if (Modifier.isStatic(method.getModifiers())) {
    
    
                    if (logger.isWarnEnabled()) {
    
    
                        logger.warn("Autowired annotation is not supported on static methods: " + method);
                    }
                    return;
                }
                if (method.getParameterCount() == 0) {
    
    
                    if (logger.isWarnEnabled()) {
    
    
                        logger.warn("Autowired annotation should only be used on methods with parameters: " +
                                method);
                    }
                }
                //要想获取到PropertyDescriptor 必须方法名为SetMethod() 如:setSpringService
                PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
                //同理
                currElements.add(new MethodInjectedElement(method, pd));
            }
        });
        // 如当前的Metadata的就会将TestRPC的元信息生成InjectionMetadata
        // 不符合的元信息正常执行(injectedElements为null),只处理有Autowired注解且是BASE_PACKAGES中的接口
        //InjectionMetadata.inject遍历 此时方法和属性就会使用我们自定义的InjectedElement去处理
        return new InjectionMetadata(clazz, currElements);
    }

    /**
     * 判断是否有Autowired注解且是BASE_PACKAGES中的接口
     */
    private static boolean isTarget(Field field) {
    
    
        return Objects.nonNull(getAnnotation(field, ANNOTATION))
                && field.getType().getName().startsWith(BASE_PACKAGES);
    }

    /**
     * 判断是否有Autowired注解且是BASE_PACKAGES中的接口
     */
    private static boolean isTarget(Method method) {
    
    
        return Objects.nonNull(getAnnotation(method, ANNOTATION))
                && method.getParameterCount() == 1
                && method.getParameterTypes()[0].getName().startsWith(BASE_PACKAGES);
    }

    /**
     * 获取被注入的实例
     */
    private Object getInjectedObject(Class<?> injectedType) {
    
    
        String cacheKey = injectedType.getName();

        Object injectedObject = injectedObjectsCache.get(cacheKey);
        //对成员属性进行修改需要同步
		synchronized (injectedObjectsCache) {
    
    
        if (injectedObject == null) {
    
    
            injectedObject = createProxy(injectedType);
            // Customized inject-object if necessary
            injectedObjectsCache.putIfAbsent(cacheKey, injectedObject);
        }
		}
        return injectedObject;
    }

    /**
     * 运行期生成代理对象
     *
     * @see com.hellobike.taxi.openplatform.facade.external.core.proxy.CoreFacadeProxy
     */
    private Object createProxy(Class<?> injectedType) {
    
    
        return Proxy.newProxyInstance(injectedType.getClassLoader(), new Class[]{
    
    injectedType}, new TaxiFacadeProxy<>(injectedType, applicationContext));
    }

    private class MethodInjectedElement extends InjectionMetadata.InjectedElement {
    
    

        private final Method method;

        protected MethodInjectedElement(Method method, PropertyDescriptor pd) {
    
    
            super(method, pd);
            this.method = method;
        }

         /**
         * 重写注入
         *
         * @param bean
         * @param beanName
         * @param pvs
         * @throws Throwable
         */
        @Override
        protected void inject(@NotNull Object bean, String beanName, PropertyValues pvs) throws Throwable {
    
    
           	//pd可能为null
            Class<?> injectedType = pd == null ? method.getParameterTypes()[0] : pd.getPropertyType();
            //传进来的method 跟 member相同
            Method member = (Method) this.member;
            boolean equals = method.equals(member);//true
            Object injectedObject = getInjectedObject(injectedType);

            ReflectionUtils.makeAccessible(method);
            applicationContext.getBean(beanName);
            method.invoke(bean, injectedObject);

            if (logger.isInfoEnabled()) {
    
    
                logger.info("MethodInjectedElement inject " + injectedType.getSimpleName() + " to " + beanName);
            }
        }
    }

    //如果存在FieldInjectedElement直接引用 元数据就会被执行 就会执行inject回调方法
    public class FieldInjectedElement extends InjectionMetadata.InjectedElement {
    
    

        private final Field field;

        protected FieldInjectedElement(Field field) {
    
    
            super(field, null);
            this.field = field;
        }

        @Override
        protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
    
    
            Class<?> injectedType = field.getType();

            Object injectedObject = getInjectedObject(injectedType);
            //打破封装
            ReflectionUtils.makeAccessible(field);
            //为bean 设置值(内存地址引用)
            //当当前field已经被注入spring bean生命周期完成 其他的postProcess就不会进行处理

            field.set(bean, injectedObject);

            if (logger.isInfoEnabled()) {
    
    
                logger.info("FieldInjectedElement inject " + injectedType.getSimpleName() + " to " + beanName);
            }
        }
    }
}

3.使用该处理器

在这里插入图片描述
在这里插入图片描述

4.对应包的接口

/**
 * @create 2021-09-26 8:13 下午
 */
public interface SpringService extends Supplier<Integer> {
    
    

    String test(Integer integer);

}

5.编写controller测试

运行期间TestRPC 的这个时候属性field SpringService 就属于有Autowired注解且是BASE_PACKAGES中的接口。此时它就会被代理成我们自定义的proxy 当我们在调用SpringService 的方法就会调用CoreFacadeProxy 的invoke方法去动态代理生成的实例方法(本例子是做了一个策略模式)

/**
 * @create 2021-09-27 10:26 上午
 */
@RestController
public class TestRPC {
    
    
	
    @Autowired
    private SpringService springService;

    @RequestMapping("/test/{id}")
    public String getSpringService(@PathVariable("id") Integer id) {
    
    
        return springService.test(id);
    }
}

猜你喜欢

转载自blog.csdn.net/qq_42261668/article/details/121447092