zl程序教程

您现在的位置是:首页 >  后端

当前栏目

spring AbstractBeanDefinition创建bean类型是动态代理类的方式

Spring代理 创建 方式 类型 动态 bean
2023-09-27 14:20:23 时间

1.接口 Class<?> resourceClass

2.获取builder

BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(resourceClass);

3.获取接口对应的动态代理class

Class<?> targetProxyClass = Proxy.getProxyClass(XXX.class.getClassLoader(), new Class[]{resourceClass});

4.targetProxyClass构造参数类型 InvocationHandler,通过builder设置

   builder.addConstructorArgValue(Proxy.getInvocationHandler(xxxProxyBean) 或者 new InvocationHandler(){...});

 AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();

   beanDefinition.setBeanClass(targetProxyClass);

   registry.registerBeanDefinition("beanName", beanDefinition);

 

5.记录一下自己曾经写的一个例子

5.1 抽象类ProxyFactoryBean

package com.hjzgg.apigateway.soa.proxy;

import com.hjzgg.apigateway.soa.exceptions.SoaException;
import com.hjzgg.apigateway.soa.proxy.consumer.ConsumerProxyFactoryBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.util.ClassUtils;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * Created by hujunzheng on 2017/7/7.
 */
public abstract class ProxyFactoryBean implements FactoryBean {

    protected Class<?> selfDynamicProxyClass;//代理类
    protected Class<?> resourceClass;//接口类
    protected String version;//dubbo 版本
    protected String group;//dubbo 分组
    protected Object proxy;//代理对象
    protected Method createProxyMethod;

    public ProxyFactoryBean(Class<?> selfDynamicProxyClass, Class<?> resourceClass, String version, String group) throws SoaException {
        if (Objects.isNull(selfDynamicProxyClass)) {
            throw new SoaException("selfDynamicProxyClass 动态代理类不能为null");
        }
        try {
            this.createProxyMethod = Stream.of(selfDynamicProxyClass.getMethods())
                    .filter(method -> Modifier.isStatic(method.getModifiers())
                            && Modifier.isPublic(method.getModifiers())
                            && !Modifier.isAbstract(method.getModifiers())
                            && method.getParameters().length == 2
                            && method.getParameters()[0].getType().equals(ProxyFactoryBean.class)
                            && method.getParameters()[1].getType().equals(Class.class)
                            && !method.getReturnType().equals(void.class))
                    .collect(Collectors.toList())
                    .get(0);
        } catch (Exception e) {
            throw new SoaException("500", String.format("%s %s %s和%s %s, %s %s"
                    , ClassUtils.getQualifiedName(selfDynamicProxyClass)
                    , " 没有参数类型是 "
                    , ClassUtils.getQualifiedName(ConsumerProxyFactoryBean.class)
                    , ClassUtils.getQualifiedName(Class.class)
                    , " 的、公共的、非抽象的、返回值非void的方法"
                    , "请将你的动态代理类继承"
                    , ClassUtils.getQualifiedName(DynamicProxyAdapter.class)
            ), e);
        }

        this.selfDynamicProxyClass = selfDynamicProxyClass;
        this.resourceClass = resourceClass;
        this.version = version;
        this.group = group;
    }

    protected Object newInstance() throws SoaException {
        if(this.isSingleton() && this.proxy != null) {
            return proxy;
        }
        synchronized (this) {
            Object target;
            try {
                target = this.createProxyMethod.invoke(null,this, selfDynamicProxyClass);
            } catch (Exception e) {
                throw new SoaException("500", String.format("%s %s %s"
                        , ClassUtils.getQualifiedName(selfDynamicProxyClass)
                        , createProxyMethod.getName()
                        , "创建代理类异常")
                        , e);
            }
            if(proxy == null) {
                proxy = target;
            }
            return target;
        }
    }

    public Class<?> getSelfDynamicProxyClass() {
        return selfDynamicProxyClass;
    }

    public void setSelfDynamicProxyClass(Class<?> selfDynamicProxyClass) {
        this.selfDynamicProxyClass = selfDynamicProxyClass;
    }

    public Class<?> getResourceClass() {
        return resourceClass;
    }

    public void setResourceClass(Class<?> resourceClass) {
        this.resourceClass = resourceClass;
    }

    public String getVersion() {
        return version;
    }

    public void setVersion(String version) {
        this.version = version;
    }

    public String getGroup() {
        return group;
    }

    public void setGroup(String group) {
        this.group = group;
    }
}

5.2 ProxyFactoryBean具体实现类ProviderProxyFactoryBean

package com.hjzgg.apigateway.soa.proxy.provider;

import com.hjzgg.apigateway.soa.exceptions.SoaException;
import com.hjzgg.apigateway.soa.proxy.ProxyFactoryBean;
import org.springframework.aop.SpringProxy;
import org.springframework.aop.TargetClassAware;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @author hujunzheng
 * @create 2018-02-18 下午3:01
 **/
public class ProviderProxyFactoryBean extends ProxyFactoryBean {
    public ProviderProxyFactoryBean(Class<?> selfDynamicProxyClass, Class<?> resourceClass, String version, String group) throws SoaException {
        super(selfDynamicProxyClass, resourceClass, version, group);
    }

    @Override
    public Object getObject() throws Exception {
        return this.newInstance();
    }

    @Override
    public Class<?> getObjectType() {
        return resourceClass;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

    public static Class<?> getProxyClass(Class<?> resourceClass) {
        /**
         * @see com.hjzgg.apigateway.dubbo.configure.SelfDubboAnnotationBean#postProcessAfterInitialization(Object, String)
         * @see org.springframework.aop.support.AopUtils#isAopProxy(Object)
         * @see org.springframework.aop.support.AopUtils#getTargetClass(Object)
         * @see com.hjzgg.apigateway.soa.proxy.provider.ProviderDynamicProxy#invoke(Object, Method, Object[])
         * */
        return Proxy.getProxyClass(ProviderProxyFactoryBean.class.getClassLoader(), new Class[]{resourceClass, SpringProxy.class, TargetClassAware.class});
    }
}

5.3 动态代理适配器DynamicProxyAdapter

package com.hjzgg.apigateway.soa.proxy;

import com.hjzgg.apigateway.soa.exceptions.SoaException;
import org.springframework.util.ClassUtils;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @author hujunzheng
 * @create 2018-02-04 上午12:00
 **/
public class DynamicProxyAdapter implements InvocationHandler {
    public DynamicProxyAdapter(ProxyFactoryBean factoryBean) {
        this.bean = factoryBean;
    }

    protected ProxyFactoryBean bean;

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        throw new SoaException(String.format("%s %s %s", "你应当重写", ClassUtils.getQualifiedName(DynamicProxyAdapter.class), "invoke方法"));
    }

    public static Object createJDKProxy(ProxyFactoryBean factoryBean, Class<?> selfDynamicProxyClass) throws SoaException {
        if (!DynamicProxyAdapter.class.equals(selfDynamicProxyClass.getSuperclass())) {
            throw new SoaException(String.format("%s %s %s"
                    , ClassUtils.getQualifiedName(selfDynamicProxyClass)
                    , "需要继承"
                    , ClassUtils.getQualifiedName(DynamicProxyAdapter.class)
            ));
        }
        Object selfDynamicProxyInstance;
        try {
            selfDynamicProxyInstance = selfDynamicProxyClass.getConstructor(factoryBean.getClass()).newInstance(factoryBean);
        } catch (Exception e) {
            throw new SoaException("500", "动态代理类创建失败", e);
        }
        Object proxy = Proxy.newProxyInstance(selfDynamicProxyClass.getClassLoader(),
                new Class[]{factoryBean.getResourceClass()}, (InvocationHandler) selfDynamicProxyInstance);
        return proxy;
    }
}

5.4 继承DynamicProxyAdapter 实现invoke接口 ProviderDynamicProxy

package com.hjzgg.apigateway.soa.proxy.provider;

import com.hjzgg.apigateway.commons.utils.ContextUtils;
import com.hjzgg.apigateway.soa.annotation.SOAImplements;
import com.hjzgg.apigateway.soa.exceptions.SoaException;
import com.hjzgg.apigateway.soa.proxy.DynamicProxyAdapter;
import com.hjzgg.apigateway.soa.proxy.consumer.ConsumerProxyFactoryBean;
import org.springframework.aop.TargetClassAware;
import org.springframework.util.ClassUtils;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;

public class ProviderDynamicProxy extends DynamicProxyAdapter {

    private static final ConcurrentHashMap<Class<?>, Object> map = new ConcurrentHashMap<>();

    public ProviderDynamicProxy(ProviderProxyFactoryBean factoryBean) {
        super(factoryBean);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        try {
            if (method.equals(TargetClassAware.class.getMethod("getTargetClass", new Class[]{}))) {
                return bean.getResourceClass();
            }
            return method.invoke(this.findRelevantServiceProvider(), args);
        } catch (Exception e) {
            throw new SoaException("500", String.format("%s %s %s"
                    , "invoke service proxy object error!"
                    , ClassUtils.getQualifiedName(this.bean.getResourceClass())
                    , method.getName()
            ), e);
        }
    }

    private Object findRelevantServiceProvider() throws SoaException {
        Class<?> resourceClass = super.bean.getResourceClass();

        if (!map.contains(resourceClass)) {
            Stream<?> stream = ContextUtils.getBeans(SOAImplements.class)
                    .stream()
                    .filter(serviceProvider -> resourceClass.isAssignableFrom(serviceProvider.getClass()));
            if (stream.count() > 1) {
                throw new SoaException(String.format(
                        "multiple relevant service provider found with annotation %s and interface is %s"
                        , ClassUtils.getQualifiedName(SOAImplements.class)
                        , ClassUtils.getQualifiedName(resourceClass))
                );
            }

            if (stream.count() == 1) {
                map.put(resourceClass, stream.findFirst().get());
            } else {
                List<?> objects = ContextUtils.getBeans(SOAImplements.class);
                if (objects.size() > 1) {
                    throw new SoaException(String.format(
                            "multiple relevant service provider found with annotation %s"
                            , ClassUtils.getQualifiedName(SOAImplements.class))
                    );
                }

                if (objects.size() == 1) {
                    map.put(resourceClass, objects.get(0));
                } else {
                    try {
                        Object object = ContextUtils.getBean(resourceClass);
                        map.put(resourceClass, object);
                    } catch (Exception e) {
                        throw new SoaException("500", String.format(
                                "find relevant service provider with interface %s error"
                                , ClassUtils.getQualifiedName(resourceClass)), e
                        );
                    }
                }
            }
        }

        return map.get(resourceClass);
    }
}

5.5 注册类型是jdk proxy类型的bean

//参数dynamicProxyClass 是 ProviderDynamicProxy
public static boolean registerProvider(BeanDefinitionRegistry registry, Class<?> dynamicProxyClass, Class<?> resourceClass) {
    String apiClassInfo = ClassUtils.getQualifiedName(resourceClass);
    try {
        /**
         * 通过代理bean的方式创建创建 服务bean
         * @see com.hjzgg.apigateway.dubbo.configure.SelfDubboAnnotationBean#postProcessAfterInitialization(Object, String)
         * if (AopUtils.isAopProxy(bean)), 判断bean的类型如果是代理类型,进行dubbo注解解析处理
         * */
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(resourceClass);
        String dubboVersion = resourceClass.getAnnotation(Service.class).version();
        String dubboGroup = resourceClass.getAnnotation(Service.class).group();
        ProviderProxyFactoryBean providerProxyFactoryBean = new ProviderProxyFactoryBean(dynamicProxyClass, resourceClass, dubboVersion, dubboGroup);
        /**
         * providerProxyFactoryBean.getObject() 得到的是通过 Proxy.newInstance方法获取到的代理类
         * @see com.hjzgg.apigateway.soa.proxy.DynamicProxyAdapter#createJDKProxy(ProxyFactoryBean, Class)
         * 可通过 Proxy.getInvocationHandler方法拿到 InvocationHandler实例
         */
        Class<?> targetProxyClass = ProviderProxyFactoryBean.getProxyClass(resourceClass);
        builder.addConstructorArgValue(Proxy.getInvocationHandler(providerProxyFactoryBean.getObject()));
        AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
        beanDefinition.setBeanClass(targetProxyClass);

        beanDefinition.setAttribute(Constants.API_CLASS_INFO, resourceClass);
        String beanName = beanNameGenerator.generateBeanName(beanDefinition, registry);
        if (registry.containsBeanDefinition(beanName)) {
            log.debug(beanName + " already exists! Class is " + apiClassInfo + " .");
            return false;
        }
        registry.registerBeanDefinition(beanName, beanDefinition);
        return true;
    } catch (Exception e) {
        log.error("registerProvider proxy bean error! Class is " + apiClassInfo + " .");
        return false;
    }
}

5.6 附加SelfDubboAnnotationBean

package com.hjzgg.apigateway.dubbo.configure;

import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.logger.Logger;
import com.alibaba.dubbo.common.logger.LoggerFactory;
import com.alibaba.dubbo.common.utils.ConcurrentHashSet;
import com.alibaba.dubbo.config.*;
import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.dubbo.config.spring.ReferenceBean;
import com.alibaba.dubbo.config.spring.ServiceBean;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.util.ClassUtils;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @see com.alibaba.dubbo.config.spring.AnnotationBean
 */
public class SelfDubboAnnotationBean extends AbstractConfig implements DisposableBean, BeanPostProcessor, ApplicationContextAware, Serializable {

    private static final Logger logger = LoggerFactory.getLogger(Logger.class);

    private String annotationPackage;

    private String[] annotationPackages;

    private final Set<ServiceConfig<?>> serviceConfigs = new ConcurrentHashSet<>();

    private final ConcurrentMap<String, ReferenceBean<?>> referenceConfigs = new ConcurrentHashMap<>();

    public String getPackage() {
        return annotationPackage;
    }

    public void setPackage(String annotationPackage) {
        this.annotationPackage = annotationPackage;
        this.annotationPackages = (annotationPackage == null || annotationPackage.length() == 0) ? null
                : Constants.COMMA_SPLIT_PATTERN.split(annotationPackage);
    }

    private ApplicationContext applicationContext;

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

    public void destroy() throws Exception {
        for (ServiceConfig<?> serviceConfig : serviceConfigs) {
            try {
                serviceConfig.unexport();
            } catch (Throwable e) {
                logger.error(e.getMessage(), e);
            }
        }
        for (ReferenceConfig<?> referenceConfig : referenceConfigs.values()) {
            try {
                referenceConfig.destroy();
            } catch (Throwable e) {
                logger.error(e.getMessage(), e);
            }
        }
    }

    public Object postProcessAfterInitialization(Object bean, String beanName)
            throws BeansException {
        if (! isMatchPackage(bean)) {
            return bean;
        }
        if (AopUtils.isAopProxy(bean)) {
            /**
             * @see com.hjzgg.apigateway.soa.executor.RegisterBeanUtils#registerProvider
             * @see com.hjzgg.apigateway.soa.proxy.provider.ProviderDynamicProxy#invoke
             * */
            //获取被代理的真实类或者接口类
            Class<?> targetClass = AopUtils.getTargetClass(bean);
            Service service = targetClass.getAnnotation(Service.class);
            if (service != null) {
                ServiceBean<Object> serviceConfig = new ServiceBean<Object>(service);
                if (void.class.equals(service.interfaceClass())
                        && "".equals(service.interfaceName())) {
                    if (!(targetClass.isInterface() || targetClass.getInterfaces().length > 0)) {
                        throw new IllegalStateException("Failed to export remote service class " + bean.getClass().getName() + ", cause: The @Service undefined interfaceClass or interfaceName, and the service class unimplemented any interfaces.");
                    } else {
                        if (targetClass.isInterface()) {
                            serviceConfig.setInterface(targetClass);
                        }

                        if (targetClass.getInterfaces().length > 0) {
                            serviceConfig.setInterface(targetClass.getInterfaces()[0]);
                        }
                    }
                }
                if (applicationContext != null) {
                    serviceConfig.setApplicationContext(applicationContext);
                    if (service.registry() != null && service.registry().length > 0) {
                        List<RegistryConfig> registryConfigs = new ArrayList<RegistryConfig>();
                        for (String registryId : service.registry()) {
                            if (registryId != null && registryId.length() > 0) {
                                registryConfigs.add(applicationContext.getBean(registryId, RegistryConfig.class));
                            }
                        }
                        serviceConfig.setRegistries(registryConfigs);
                    }
                    if (service.provider() != null && service.provider().length() > 0) {
                        serviceConfig.setProvider(applicationContext.getBean(service.provider(),ProviderConfig.class));
                    }
                    if (service.monitor() != null && service.monitor().length() > 0) {
                        serviceConfig.setMonitor(applicationContext.getBean(service.monitor(), MonitorConfig.class));
                    }
                    if (service.application() != null && service.application().length() > 0) {
                        serviceConfig.setApplication(applicationContext.getBean(service.application(), ApplicationConfig.class));
                    }
                    if (service.module() != null && service.module().length() > 0) {
                        serviceConfig.setModule(applicationContext.getBean(service.module(), ModuleConfig.class));
                    }
                    if (service.provider() != null && service.provider().length() > 0) {
                        serviceConfig.setProvider(applicationContext.getBean(service.provider(), ProviderConfig.class));
                    }
                    if (service.protocol() != null && service.protocol().length > 0) {
                        List<ProtocolConfig> protocolConfigs = new ArrayList<ProtocolConfig>();
                        for (String protocolId : service.registry()) {
                            if (protocolId != null && protocolId.length() > 0) {
                                protocolConfigs.add(applicationContext.getBean(protocolId, ProtocolConfig.class));
                            }
                        }
                        serviceConfig.setProtocols(protocolConfigs);
                    }
                    try {
                        serviceConfig.afterPropertiesSet();
                    } catch (RuntimeException e) {
                        throw e;
                    } catch (Exception e) {
                        throw new IllegalStateException(e.getMessage(), e);
                    }
                }
                serviceConfig.setRef(bean);
                serviceConfigs.add(serviceConfig);
                serviceConfig.export();
            }
        }
        return bean;
    }

    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {

        Service service = (AopUtils.isAopProxy(bean) && !Objects.isNull(AopUtils.getTargetClass(bean).getAnnotation(Service.class)))
                ? AopUtils.getTargetClass(bean).getAnnotation(Service.class)
                : bean.getClass().getAnnotation(Service.class);
        if (Objects.isNull(service)) {
            return bean;
        }
        try {
            InvocationHandler h = Proxy.getInvocationHandler(service);

            // 获取 AnnotationInvocationHandler 的 memberValues 字段
            Field memberValuesField = h.getClass().getDeclaredField("memberValues");
            // 因为这个字段事 private final 修饰,所以要打开权限
            memberValuesField.setAccessible(true);
            // 获取 memberValues
            Map memberValues = (Map) memberValuesField.get(h);

            Service serviceInstance = Stream.of(bean.getClass().getInterfaces())
                    .filter(iface -> iface.getAnnotation(Service.class) != null)
                    .collect(Collectors.toList())
                    .get(0)
                    .getAnnotation(Service.class);

            memberValues.put("version", serviceInstance.version());
            memberValues.put("group", serviceInstance.group());
        } catch (Exception e) {
            throw new BeanCreationException(String.format("%s %s %s %s %s"
                    , "修改"
                    , ClassUtils.getQualifiedName(bean.getClass())
                    , "的注解"
                    , ClassUtils.getQualifiedName(Service.class)
                    , "的 group值和version值出错")
                    , e);
        }
        return bean;
    }


    private boolean isMatchPackage(Object bean) {
        if (annotationPackages == null || annotationPackages.length == 0) {
            return true;
        }
        String beanClassName = bean.getClass().getName();
        for (String pkg : annotationPackages) {
            if (beanClassName.startsWith(pkg)) {
                return true;
            }
        }
        return false;
    }

}
View Code

 5.7 附加AopUtils相关方法

/**
 * Check whether the given object is a JDK dynamic proxy or a CGLIB proxy.
 * <p>This method additionally checks if the given object is an instance
 * of {@link SpringProxy}.
 * @param object the object to check
 * @see #isJdkDynamicProxy
 * @see #isCglibProxy
 */
public static boolean isAopProxy(Object object) {
    return (object instanceof SpringProxy &&
            (Proxy.isProxyClass(object.getClass()) || ClassUtils.isCglibProxyClass(object.getClass())));
}


/**
 * Determine the target class of the given bean instance which might be an AOP proxy.
 * <p>Returns the target class for an AOP proxy or the plain class otherwise.
 * @param candidate the instance to check (might be an AOP proxy)
 * @return the target class (or the plain class of the given object as fallback;
 * never {@code null})
 * @see org.springframework.aop.TargetClassAware#getTargetClass()
 * @see org.springframework.aop.framework.AopProxyUtils#ultimateTargetClass(Object)
 */
public static Class<?> getTargetClass(Object candidate) {
    Assert.notNull(candidate, "Candidate object must not be null");
    Class<?> result = null;
    if (candidate instanceof TargetClassAware) {
        result = ((TargetClassAware) candidate).getTargetClass();
    }
    if (result == null) {
        result = (isCglibProxy(candidate) ? candidate.getClass().getSuperclass() : candidate.getClass());
    }
    return result;
}
View Code