通过注解动态指定实现类,实现spring bean的动态代理

当我们的一个接口需要被多次实现时,如果不用动态代理或者实现类,那么我们的代码就会十分的冗余,到处都是impl的实现类注入,很不友好。为此,我们可以通过动态代理类,将生成的对象注入到Spring容器中,业务层只要继承我们的上游接口,再通过注解指定名称的方式达到实时动态获取实现类。

实现动态代理需要实现的类如下

  • BeanDefinitionRegistryPostProcessor

实现自定义的注册bean定义的逻辑,官方解释

/**

 * Extension to the standard {@link BeanFactoryPostProcessor} SPI, allowing for

 * the registration of further bean definitions <i>before</i> regular

 * BeanFactoryPostProcessor detection kicks in. In particular,

 * BeanDefinitionRegistryPostProcessor may register further bean definitions

 * which in turn define BeanFactoryPostProcessor instances.

 **/

  • ApplicationContextAware

实现这个接口可以方便的获取所有的bean

  • FactoryBean

由{@link BeanFactory}中使用的对象实现本身就是单个对象的工厂。如果bean实现了这个接口,它被用作对象公开的工厂,而不是直接作为将自己公开的Bean实例。

  • InvocationHandler

代理实现类的处理器

demo联系

需要应用的依赖


        <dependency>

            <groupId>org.reflections</groupId>

            <artifactId>reflections</artifactId>

            <version>0.9.10</version>

        </dependency>

先定义好自己的注解,为后续方法上指定做准备


工作类型注解,工作实现的方法上使用该注解

import java.lang.annotation.*;



@Documented

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.TYPE)

public @interface WorkHandoverType {



    String type();



}

工作默认实现类注解


@Documented

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.TYPE)

public @interface HandlerWorkAutoImpl {



    String name();



}

自定义factorybean----HandlerInterfaceFactoryBean


import lombok.Data;

import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.FactoryBean;

import org.springframework.context.ApplicationContext;





@Slf4j

@Data

public class HandlerInterfaceFactoryBean<T> implements FactoryBean<T> {



    private Class<T> interfaceClass;



    private String typeName;



    private ApplicationContext context;



    @Override

    public T getObject() {

        return (T) DynamicProxyBeanFactory.newMapperProxy(typeName, context, interfaceClass);

    }



    @Override

    public Class<?> getObjectType() {

        return interfaceClass;

    }



    @Override

    public boolean isSingleton() {

        return true;

    }

}

实现InvocationHandler


package io.hcbm.boot.wm.dynamic;



import io.hcbm.boot.wm.annotation.WorkHandoverType;

import lombok.extern.slf4j.Slf4j;

import org.springframework.context.ApplicationContext;



import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.lang.reflect.Proxy;

import java.util.HashMap;

import java.util.Map;





@Slf4j

public class DynamicProxyBeanFactory implements InvocationHandler {



    private String className;



    private ApplicationContext applicationContext;



    private Map<String, Object> clientMap = new HashMap<>();



    public DynamicProxyBeanFactory(String className, ApplicationContext applicationContext) {

        this.className = className;

        this.applicationContext = applicationContext;

    }



    @Override

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        if (clientMap.size() == 0) {

            initClientMap();

        }

        String workType = (String) args[0];

        return clientMap.get(workType);

    }



    private void initClientMap() throws ClassNotFoundException {

        Map<String,?> classMap = applicationContext.getBeansOfType(Class.forName(className));

        log.info("DynamicProxyBeanFactory className: [{}] , impl class: [{}]",className,classMap);



        for (Map.Entry<String,?> entry : classMap.entrySet()) {
          //这里注意下,获取注解别名,显式别名、隐式别名、传递的隐式别名,用这个方法,可能service层直接通过class获取不到。
          WorkHandoverType workHandoverType = AnnotationUtils.findAnnotation(entry.getValue().getClass(),
                    WorkHandoverType.class);
            if (workHandoverType == null) {

                continue;

            }

            clientMap.put(workHandoverType.type(), entry.getValue());

        }

        log.info("DynamicProxyBeanFactory clientMap: [{}]",clientMap);

    }



    public static <T> T newMapperProxy(String classStr,ApplicationContext applicationContext,Class<T> mapperInterface) {

        ClassLoader classLoader = mapperInterface.getClassLoader();

        Class<?>[] interfaces = new Class[] {mapperInterface};

        DynamicProxyBeanFactory proxy = new DynamicProxyBeanFactory(classStr, applicationContext);

        return (T) Proxy.newProxyInstance(classLoader, interfaces, proxy);

    }

}



自定义实现HandlerBeanDefinitionRegistry


package io.hcbm.boot.wm.dynamic;



import io.hcbm.boot.wm.annotation.HandlerWorkAutoImpl;

import lombok.extern.slf4j.Slf4j;



import org.reflections.Reflections;

import org.reflections.scanners.SubTypesScanner;

import org.reflections.scanners.TypeAnnotationsScanner;

import org.springframework.beans.BeansException;

import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

import org.springframework.beans.factory.support.BeanDefinitionBuilder;

import org.springframework.beans.factory.support.BeanDefinitionRegistry;

import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;

import org.springframework.beans.factory.support.GenericBeanDefinition;

import org.springframework.context.ApplicationContext;

import org.springframework.context.ApplicationContextAware;

import org.springframework.stereotype.Component;



import java.lang.reflect.ParameterizedType;

import java.lang.reflect.Type;

import java.util.Set;





@Slf4j

@Component

public class HandlerBeanDefinitionRegistry implements BeanDefinitionRegistryPostProcessor, ApplicationContextAware {



    private static final String INTERFACE_CLASS = "interfaceClass";

    private static final String TYPE_NAME = "typeName";

    private static final String CONTEXT = "context";



    private ApplicationContext applicationContext;



    @Override

    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {



        Set<Class<?>> classes = getAutoWorkClasses();

        for (Class<?> clazz : classes) {

            Type[] types = clazz.getGenericInterfaces();

            ParameterizedType type = (ParameterizedType) types[0];

            String typeName = type.getActualTypeArguments()[0].getTypeName();



            HandlerWorkAutoImpl handlerRouterAutoImpl = clazz.getAnnotation(HandlerWorkAutoImpl.class);

            BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(clazz);

            GenericBeanDefinition definition = (GenericBeanDefinition) builder.getRawBeanDefinition();



            definition.getPropertyValues().add(INTERFACE_CLASS, clazz);

            definition.getPropertyValues().add(TYPE_NAME, typeName);

            definition.getPropertyValues().add(CONTEXT, applicationContext);



            definition.setBeanClass(HandlerInterfaceFactoryBean.class);

            definition.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_TYPE);

            beanDefinitionRegistry.registerBeanDefinition(handlerRouterAutoImpl.name(), definition);

        }

    }



    @Override

    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

    }



    private Set<Class<?>> getAutoWorkClasses() {

        Reflections reflections = new Reflections(

                "io.hcbm.*",//这里包路径改为自己的

                new TypeAnnotationsScanner(),

                new SubTypesScanner());



        return reflections.getTypesAnnotatedWith(HandlerWorkAutoImpl.class);

    }



    @Override

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

        this.applicationContext = applicationContext;

    }



}

以上我们的动态代理需要重新实现的方法完成*

开始业务层的demo coding

抽象一个HandlerRouter范型接口


public interface HandlerRouter<T> {



    /**

     * 工作交接处理方法

     * @param workType 工作交接类型

     * @param args 参数

     * @return T

     */

    T workHandler(String workType, Object... args);

}

创建我们需要的工作接口定义


public interface WorkHandler {



    /**

     * 工作交接执行方法

     * @param workType 工作交接类型

     * @param obj obj

     */

    void invoke(String workType, Object obj);



}

再抽象一层工作的接口,同时在接口上添加@HandlerWorkAutoImpl注解


import io.hcbm.boot.wm.annotation.HandlerWorkAutoImpl;





@HandlerWorkAutoImpl(name = "workHandlerRouter")

public interface WorkHandlerRouter extends HandlerRouter<WorkHandler> {



    /**

     *

     * @param workType

     * @return

     */

    WorkHandler getWorkHandler(String workType);



}

创建工作的controller


import com.alibaba.fastjson.JSONObject;

import io.hcbm.boot.wm.service.WorkHandler;

import io.hcbm.boot.wm.service.WorkHandlerRouter;

import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.http.ResponseEntity;

import org.springframework.web.bind.annotation.*;





@Slf4j

@RestController

@RequestMapping("/v1/work")

public class WorkHandoverController {



    @Autowired

    private WorkHandlerRouter deviceHandlerRouter;



    @GetMapping

    @Permission(permissionPublic = true)

    public ResponseEntity<Object> test() {



        WorkHandler work01 = deviceHandlerRouter.workHandler("work01",null);

        System.out.println("----WorkHandler---实现类-->" + work01);



        WorkHandler work02 = deviceHandlerRouter.workHandler("work02", null);

        System.out.println("----WorkHandler---实现类-->" + work02);

        return ResponseEntity.ok("success");

    }

    

}



创建两个工作的实现demo类


import io.hcbm.boot.wm.annotation.WorkHandoverType;

import io.hcbm.boot.wm.service.WorkHandler;

import lombok.extern.slf4j.Slf4j;

import org.springframework.stereotype.Component;



@WorkHandoverType(type = "work01")

@Component

@Slf4j

public class Work01HandlerImpl implements WorkHandler {



    @Override

    public void invoke(String workType, Object obj) {

        System.out.println("Work01HandlerImpl---------> " + workType);

    }

}





import io.hcbm.boot.wm.annotation.WorkHandoverType;

import io.hcbm.boot.wm.service.WorkHandler;

import lombok.extern.slf4j.Slf4j;

import org.springframework.stereotype.Component;



@WorkHandoverType(type = "work02")

@Component

@Slf4j

public class Work02HandlerImpl implements WorkHandler {



    @Override

    public void invoke(String workType, Object obj) {

        System.out.println("Work02HandlerImpl---------> " + workType);

    }

}

运行结果

  • 可以发现,我们没有实现具体的impl,但通过传参数可以动态指定具体实现哪个service
posted @ 2022-07-16 21:31  Levcon  阅读(1182)  评论(0编辑  收藏  举报