zoukankan      html  css  js  c++  java
  • spring AbstractBeanDefinition创建bean类型是动态代理类的方式

    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
  • 相关阅读:
    【实战】Weblogic xmldecoder反序列化Getshell
    【实战】JBOSS反序列化Getshell
    【实战】Tomcat管理后台Getshell
    【Python】二进制转ASCII码小脚本
    【实战】sqlmap显示有注入却无法爆出库名
    【总结】APP客户端渗透测试
    【总结】Struts2系列漏洞POC小结
    【Python】端口扫描脚本
    2020中国高校计算机大赛 华为云大数据挑战赛--热身赛--爬取天气数据
    2020中国高校计算机大赛 华为云大数据挑战赛--热身赛--赛题分析、数据理解
  • 原文地址:https://www.cnblogs.com/hujunzheng/p/8527338.html
Copyright © 2011-2022 走看看