spring动态注册bean

最近在开发一个springboot项目,使用https接口与客户系统进行交互,我方提供服务端,但是客户想用通过HttpInvoker 的方式进行调用,此篇文章暂时不介绍HttpInvoker,在此介绍如何动态的吧相关的实现动态的发布成HTTPInvoker服务。

首先开发一个标记接口,所有的实现此接口的类都将被动态的注册成HTTPInvoker 服务

package com.baiwang.custom.web.base;

import java.io.Serializable;

/**
 * @author wjh
 * @Description HTTPInvoker 服务发布标记接口,默认实现序列化
 * @date 20180605
 * 
 */
public interface HTTPInvokerService extends Serializable{
	

}


业务接口

package com.baiwang.custom.web.service;

public interface IUserTest {
	
	public String getAll();

}


业务实现类

package com.baiwang.custom.web.service.impl;

import org.springframework.stereotype.Service;
import com.baiwang.custom.web.base.HTTPInvokerService;
import com.baiwang.custom.web.service.IUserTest;

@Service
public class UserTestImpl implements IUserTest, HTTPInvokerService {

	private static final long serialVersionUID = 1L;

	@Override
	public String getAll() {
		System.out.println("====>getAll Test 123");
		// TODO Auto-generated method stub
		return null;
	}

}

注册类

package com.baiwang.custom.web.base;

import java.util.Properties;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;


/**
 * @author wjh
 * @version 0.1
 * @Description 本类是用来提供 容器上下文<link>ApplicationContext</link> 和容器注册器<link>BeanDefinitionRegistryPostProcessor</link>,
 * 				当前版本实现个性化的HTTPInvoker服务的动态发布注册。
 * @param ContextRefreshedEvent 
 */
@Component
public class BeanUtil implements ApplicationContextAware, BeanDefinitionRegistryPostProcessor {

	private static Logger logger = LoggerFactory.getLogger(BeanUtil.class);
	//容器上下文
	public static ApplicationContext applicationContext;
	//容器注册器
	private static BeanDefinitionRegistry registry;

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		BeanUtil.applicationContext = applicationContext;
	}

	/**
	 * @Description:将bean发布成HttpInvoker服务,同时添加地址实体映射<link>SimpleUrlHandlerMapping</link>
	 * 				关于多接口实现HttpInvokerServiceExporter 实体命名规则 从0开始 依次递加
	 * @param String beanName bean名称
	 * @param T t 实体
	 */
	public static <T> void registAsInvokerBean(String beanName, T t) {
		System.out.println("========> "+t.getClass().getName());
		logger.info("==>registAsInvokerBean {} {} Begin params " +"["+beanName+"]," +"["+t+"]");
		long beginTime = System.currentTimeMillis();
		// 获取所有服务接口 不包括ApplicationContextAware,BeanDefinitionRegistryPostProcessor
		Class[] classes = t.getClass().getInterfaces();
		//接口过滤 过滤掉标记接口 HTTPInvokerService,接口需要在com.baiwang 包或子包内
		
		// 发布成invoker接口默认需要面向接口编程 如果没有实现接口编程 抛出异常
		if (classes == null || classes.length == 0) {
			throw new RuntimeException("==>注册发布Invoker bean " + beanName + "未实现面向接口编程,不能进行注册,class name :"+t.getClass().getName());
		} else {
			// 如果是多接口实现,同样基于支持,但是不包括标记接口 HTTPInvokerService
			for (int i = 0; i < classes.length; i++) {
				//获取接口名称
				String className = classes[i].getName();
				// 不包括标记接口 HTTPInvokerService,接口需要在com.baiwang 包或子包内
				if (classes[i].equals(HTTPInvokerService.class)|| !className.startsWith("com.baiwang")) {
					continue;
				}
				// 关于多接口实现HttpInvokerServiceExporter 实体命名规则 如果只有一个实际实现接口 则名字为 beanName+"Exporter" 
				// 如果存在多个 则使用beanName + i+ "Exporter"
				String exporterName = beanName + (i==0?"":i)+ "Exporter";
				// 新注册 HttpInvokerServiceExporter 的bean用作分发代理
				RootBeanDefinition beanExporter = new RootBeanDefinition(HttpInvokerServiceExporter.class);
				// 添加注册bean的属性
				MutablePropertyValues propertyValues = new MutablePropertyValues();
			
				//设置服务接口 
				propertyValues.add("serviceInterface", classes[i]);
				//设置服务bean 所有的接口用同一个bean
				propertyValues.add("service", t);
				beanExporter.setPropertyValues(propertyValues);
				// 添加注册 HttpInvokerServiceExporter 名称是实际的实现类 首字母小写 加上Exporter
				registry.registerBeanDefinition(exporterName, beanExporter);
				
				HttpInvokerServiceExporter sh2 = (HttpInvokerServiceExporter) applicationContext.getBean(exporterName);

				// 构建 实体地址映射
				String path ="/" + exporterName + ".service";
				SimpleUrlHandlerMapping sh = applicationContext.getBean(SimpleUrlHandlerMapping.class);
				Properties propetis = new Properties();
				propetis.setProperty(path, exporterName);
				sh.setMappings(propetis);
				//注册hander(设置完实体地址映射时需要初始化一下handerMapping)
				sh.initApplicationContext();
				logger.info("==>当前Invoker 服务注册信息:path:"+path +",处理接口 :"+className+"处理实现:"+t);
			}

		}
		logger.info("==>registAsInvokerBean ["+beanName+"] end time "+ (System.currentTimeMillis()-beginTime));
	}

	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory arg0) throws BeansException {
		// TODO Auto-generated method stub

	}

	@Override
	public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
		this.registry = registry;
	}
	
	 /**
     * Description :将特定的请求映射到具体的hessianservice
     * 
     */
    @Bean  
    public SimpleUrlHandlerMapping simpleUrlHandlerMapping() {
    	return new SimpleUrlHandlerMapping();
    }

}

扫描实现HTTPInvokerService 接口的类并注册为  HttpInvokerServiceExcporter 代理类,同时 将代理类注册对应的地址


附上客户端调用的代码

package com.baiwang.custom.web.controller;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;

import com.baiwang.custom.web.base.BeanUtil;
import com.baiwang.custom.web.base.MailSend;
import com.baiwang.custom.web.entity.Users;
import com.baiwang.custom.web.service.IUserTest;
import com.baiwang.custom.web.service.UserService;
import com.baiwang.platform.custom.common.result.CrRpcResult;


@RestController
@RequestMapping("/test")
public class CustomTestController {

    private static final Log logger = LogFactory.getLog(CustomTestController.class);

   @Autowired
   IUserTest invokerUserAutoTest;
   
   @Autowired
   MailSend mailSend;
    @RequestMapping(value = "/test", method = RequestMethod.GET)
    public CrRpcResult findDownloadFileUrl() {

        IUserTest us2 = (IUserTest) invokerUserAutoTest;   
        us2.getAll();
        return result;
    }

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring中,我们可以使用BeanFactory或者ApplicationContext来动态创建Bean实例。 1. 使用BeanFactory动态创建Bean实例 ```java DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(Person.class); builder.addPropertyValue("name", "张三"); builder.addPropertyValue("age", 18); beanFactory.registerBeanDefinition("person", builder.getBeanDefinition()); Person person = (Person) beanFactory.getBean("person"); ``` 以上代码中,我们先创建一个DefaultListableBeanFactory实例,然后使用BeanDefinitionBuilder创建一个BeanDefinition,指定要创建的Bean类型为Person,并设置Bean的属性值(name和age)。最后将BeanDefinition注册BeanFactory中,然后通过getBean()方法获取动态创建的Person实例。 2. 使用ApplicationContext动态创建Bean实例 ```java GenericApplicationContext context = new GenericApplicationContext(); context.refresh(); GenericBeanDefinition beanDefinition = new GenericBeanDefinition(); beanDefinition.setBeanClass(Person.class); beanDefinition.getPropertyValues().add("name", "张三"); beanDefinition.getPropertyValues().add("age", 18); context.registerBeanDefinition("person", beanDefinition); Person person = (Person) context.getBean("person"); ``` 以上代码中,我们创建了一个GenericApplicationContext实例,并调用refresh()方法初始化容器。然后创建一个GenericBeanDefinition实例,设置Bean的类型为Person,并设置Bean的属性值(name和age)。最后将BeanDefinition注册到ApplicationContext中,然后通过getBean()方法获取动态创建的Person实例。 总的来说,使用Spring动态创建Bean实例的方法比较灵活,可以根据具体的需求来选择使用BeanFactory或者ApplicationContext。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值