知识大全 加载远程服务上的spring独立子模块
Posted 知
篇首语:知是行的主意,行是知的功夫。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 加载远程服务上的spring独立子模块相关的知识,希望对你有一定的参考价值。
背景
假设一个web工程有 个独立业务子模块 user home rpc 个独立子模块也独立发布 子模块独立发布后可以及时reloadweb工程的业务功能 个子模块可以在任何服务器上 也可以是 个不同的公司来提供
一般我们的工程会采用spring来管理bean 在这种情况下要稍微改造下 看上去和热部署也有点类似
这次的知识点以这个背景为例来进行讲解
首先看下这样做的一些好处
业务模块的独立按需加载 可以加快web容器的启动 每次只需要启动时加载自己需要的内容
发布更新更快速 独立发布子模块影响局部的业务功能
原理
我们先做一个子模块user jar(在 共享里)
user jar里面就一个spring_user xml和User java
spring_user xml
<bean id= user class= wzucxd User >
<property name= name value= xxx />
</bean>
User java
package wzucxd;
public class User
private Integer id;
private String name;
public Integer getId()
return id;
public void setId(Integer id)
this id = id;
public String getName()
return name;
public void setName(String name)
this name = name;
下面就是模拟父容器加载子模块的case
基本思路 通过XmlBeanFactory先加载子模块的bean对象的BeanDefinition 然后将BeanDefinition注册到父容易的beanFactory 最后对加载bean的AppClassloader改造成需要的ClassLoader(这里改造成URLClassLoader)
详细代码以及示例如下
public class Test
public static void main(String[] args)
try
//读取spring全局配置文件 (这里是一个空内容的文件 没有任何内容) 即我们平时web project父容器上下文
//当然平时这里会用ClassPathXmlApplicationContext 看文件所在位置了…
ApplicationContextapplicationContext = newFileSystemXmlApplicationContext( file:// \\\\share\\\\ebook\\\\j se\\\\classloader\\\\spring_config xml )
//创建全局spring BeanFactory 目的是将所有子模块的bean对象注册到这个父容器上下文中
DefaultListableBeanFactorybeanFactory = (DefaultListableBeanFactory)applicationContext getAutowireCapableBeanFactory()
//独立模块的spring bean配置文件位置
String configurationFilePath = jar:file:// \\\\share\\\\ebook\\\\j se\\\\classloader/user jar!/spring_user xml ;
//这里可以做一个逻辑 如果该配置文件不存在 那么父容器启动的时候这个子模块就不加载
URL url = new URL(configurationFilePath)
//建立远程资源访问
UrlResource urlResource = new UrlResource(url)
XmlBeanFactory xmlBeanFactory = new XmlBeanFactory(urlResource)
String[] beanIds =xmlBeanFactory getBeanDefinitionNames()
for (String beanId : beanIds)
//获得的子模块bean对象
BeanDefinition bd =xmlBeanFactory getMergedBeanDefinition(beanId)
//在这里将子模块bean对象注册到父容易上下文中 完成bean对象的Definition
beanFactory registerBeanDefinition(beanId bd)
//接着要进行classloader的改变 加载的class文件现在不在classpath下 而是其他地方(远程共享 服务或者其他协议服务的机器上)
//这时候就需要将父容易中beanFactory的加载bean的classloader改变(父容易中beanFactory默认是AppClassLoader 这种情况下改成用URLClassLoader)
// 以下这行设置BeanFactory的ClassLoader为URLClassLoader 以加载外部类
setBeanClassLoader(beanFactory)
//以下是测试是否注入成功
//从父容器上下文中获取user对象
Object pluginBean =applicationContext getBean( user )
//测试结果
String val = tryInvoke(pluginBean)
System out println(val)
catch (Exception exc)
exc printStackTrace()
private static void setBeanClassLoader(
DefaultListableBeanFactorybeanFactory)
throws MalformedURLException
//指明spring_user xml配置出现的bean对象所在jar位置
String jarFilePath = file:// \\\\share\\\\ebook\\\\j se\\\\classloader\\\\user jar ;
URL jarUrl = new URL(jarFilePath)
URL[] urls = new URL[] jarUrl ;
URLClassLoader cl = new URLClassLoader(urls)
beanFactory setBeanClassLoader(cl)
private static String tryInvoke(Object bean) throws SecurityException
NoSuchMethodException IllegalArgumentException
IllegalAccessException InvocationTargetException
Class<?> paramTypes[] = new Class[ ];
Method method =bean getClass() getDeclaredMethod( getName paramTypes)
Object paramValues[] = new Object[ ];
Object obj = method invoke(bean paramValues)
//……
return (String)obj;
这里如果我们不改变BeanClassLoader会有什么问题呢?会出现classnofound异常 这个主要原因就是默认的beanfactory classloader是AppClassLoader
当然还有另外一种方式 将jar中的类扫描出来 自己创建个classloader 一个个添加进去 这种方式更加灵活多变 其实还是使用spring的bean管理方式使用比较方便 已经解决了主要场景
public static void main(String[] args) throws Exception
URL url = new URL( jar:file:d:\\\\user jar!/ )
URLClassLoader uc = new URLClassLoader(new URL[]url)
Class<?> cls = uc loadClass( wzucxd User )
Object obj = cls newInstance()
System out println(obj)
cha138/Article/program/Java/hx/201311/27186相关参考