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);
}
}