实现动态代理注入

631 阅读2分钟

突发奇想想给练手的Rpc项目中的服务免去配置动态代理的过程,直接使用AutoWired注入

这是没有配置前使用的流程

        RpcClientProxy rpcClientProxy =new RpcClientProxy(Service.class);
        Service service= rpcClientProxy.getProxy(Service.class);
        System.out.println(service.caculate(1,1));

使用将动态代理放入到容器后自动注册

@Controller
@RequestMapping("/nagi-rpc")
@CrossOrigin(origins = {"*"}, allowCredentials = "true")
public class NodeController {

    @Autowired
    NodeService nodeService;
    @Autowired
    Caculate  caculate;
    @RequestMapping("/list")
    @ResponseBody
 public List<ServiceNode> getServiceLists() throws Exception {
     return nodeService.getNodes();
 }
 @RequestMapping("/change")
 @ResponseBody
 public String changeStatus(String ServiceName) throws Exception {
        nodeService.changeStatus(ServiceName);
        return "success";
 }
 @RequestMapping("/test")
 @ResponseBody
 public String test(){
     return caculate.caculate(1,1);
 }

在test中可以直接调用服务了(Caculate)

具体实现主要还是通过Spring对Ioc容器提供的扩展点

实现类

//用于将带@RpcService的接口自动注册到Ioc容器中,并将其实现设为动态代理实现
@Component
public class ProxyBeanDefinitionRegistry implements BeanDefinitionRegistryPostProcessor{
    //带@RpcService的类
    Set<Class<?>> classes;
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
     //设置扫包路径
        this.classes=getRpcServiceClasses("");
        for(Class<?> clazz:classes){
            //生成接口的BeanDefinition
            BeanDefinitionBuilder builder=BeanDefinitionBuilder.genericBeanDefinition(clazz);
            GenericBeanDefinition definition= (GenericBeanDefinition) builder.getRawBeanDefinition();
            //设置构造方法,不然后面FactoryBean无法正常调用
            definition.getConstructorArgumentValues().addGenericArgumentValue(clazz);
            //将类设为FactoryBean
            definition.setBeanClass(ServiceFactory.class);
            //将BeanDefinition注册到容器
            registry.registerBeanDefinition(definition.getBeanClassName(), definition);
        }
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    }
    //扫包找到带对应注释的类
private Set<Class<?>> getRpcServiceClasses(String basePackage){
Reflections reflections=new Reflections(basePackage,new TypeAnnotationsScanner(),new SubTypesScanner());
return reflections.getTypesAnnotatedWith(RpcService.class);
    }
}

实习了BeanDefinitionRegistryPostProcessor接口的组价可以在bean加载进Ioc容器还未实例化前执行扩展,比如这里又通过扫描包将包含了@RpcService注释的接口注册进容器,并将类设置为

//代替Service在Bean中的类,会调用getObject返回代理类
public class ServiceFactory<T> implements FactoryBean<T> {
    private Class<T> interfaceType;

    public ServiceFactory(Class<T> interfaceType) {
        this.interfaceType = interfaceType;
    }

    @Override
    public T getObject() throws Exception {
        RpcClientProxy rpcClientProxy =new RpcClientProxy(interfaceType);
        return (T)     rpcClientProxy.getProxy(interfaceType);
    }

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

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

这里获得bean时便会调用getObject方法或者对应代理对象,也就可以将动态代理

注入了

代理对象

@Data
@AllArgsConstructor

public class RpcClientProxy implements InvocationHandler {
    /**
     * 被代理类
     */
    private final Class<?> serviceClass;
    public <T> T getProxy(Class<?> clazz){
        return (T) Proxy.newProxyInstance(clazz.getClassLoader(),new Class[]{clazz},this);
    }
    /***
     *
     * @param proxy 这个proxy的作用是啥
     * @param method
     * @param args
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        RpcRequest request =new RpcRequest(serviceClass.getName(),method.getName(), method.getParameterTypes(), args);
        RpcClientService rpcClientService = ExtensionLoader.getExtensionLoader(RpcClientService.class).getExtension("RpcClientService");
        RpcResponse response;
        if(serviceClass.getAnnotation(Dispensable.class)!=null){
           response = (RpcResponse) rpcClientService.service(request,true);
        }
        else response = (RpcResponse) rpcClientService.service(request);
        if(response.getAns()==null){
            return "服务繁忙请稍后再试";
        }
        return response.getAns();
    }
}