【200分】求JAVA框架整包切换与隔离的调用实现方式,求神代码!!!

0轰隆隆0 2015-01-13 10:06:36
加精
此贴是续前帖:http://bbs.csdn.net/topics/390967810

继续讨论JAVA框架的整包切换与隔离的实现方法,我将前帖重新整理一下,添加了详细的描述信息,分数提高到200分,希望版主大人推荐一下,期待神回复和神代码的出现!



现状:
1,entity 包下有4个类,PUB类,A类,B类和C类,还有3个包,分别是a,b,c包;
2,a包下面的X1、X2、X3....Xn和b、c包下的X1、X2、X3....Xn是对应的,里面的方法也是一样的(也就是说a包下面的X1有一个Y()方法,那对应的b、c包下面的X1也有一个Y()方法;a包下面有一个X6,那么b、c包下面也有一个X6;里面的方法名和传参都是一样的,只是具体实现可能会不一样)。
3,A类调用a包下面类的方法,B类调用b包下面类的方法,C类调用c包下面类的方法;

目的:
1,PUB类是entity 包提供下对外公开访问的类;
2,现在在PUB类里面通过参数切换A类,B类和C类,实现调用a,b,c包下面的各个类的各个方法。

描述:
1,比如PUB里面参数设置的是A类,那么通过PUB调用的就是a包下面所有的类和方法,那么b,c包下面的所有类和方法都是不可见的;
2,写A类,B类和C类的目的就是为了隔离a,b,c包,实现整包的整体切换调用,如果高人都更好的办法实现整包的切换,那就可以省略。

要求:
1,最理想的调用方式:

PUB pub = new PUB
pub.X1.Y(); //调用的时候 把a、b、c包这层隐藏掉,X1是类名,Y()就是X1的方法
//或者
pub.xxx("X1").Y(); //其中X1就是a、b、c包下的一个类,Y()就是X1的方法

2,以最简明扼要的代码实现,贴出相关代码,使观者能理解整个调用流程;
3,不要告诉我用什么模式、什么框架可以实现,要说理论我也能说出一大堆,但是自己去写又有几人能写出来呢
4,以代码最优者给全分【200】,如果都没有达到要求者,每楼层平均分配。
...全文
2910 77 打赏 收藏 转发到动态 举报
写回复
用AI写文章
77 条回复
切换为时间正序
请发表友善的回复…
发表回复
injuer 2015-06-28
  • 打赏
  • 举报
回复

接口:



package ISyaHi;



public interface ISayHi {

       public String SayHi(String name);

}



实现类:



package SayHiImp;



import ISyaHi.ISayHi;



public class SayHiEnImp implements ISayHi {

 

       public SayHiEnImp()

       {

       }



       public String SayHi(String name) {

       return "Hello! "+name.toUpperCase()+" This JAVA Word!";

}



package SayHiImp;



import ISyaHi.ISayHi;



public class SayHiZhImp implements ISayHi {

 

       public SayHiZhImp()

       {

       }

 

       public String SayHi(String name) {

              return "你好! "+name.toUpperCase()+" 这是JAVA世界!";

       }



}



控制类:



package SayHiController;



import ISyaHi.ISayHi;

import XMLPrass.XmlPrass;



public class Controller {

       private ISayHi iSatHi;

       private XmlPrass xmlPrass;

 

       public Controller ()

      {

           try{

                  xmlPrass=XmlPrass.newInstance();

                  if(xmlPrass.sax().equals("ZH")){

                          iSatHi=(ISayHi)Class.forName("SayHiImp.SayHiZhImp").newInstance();

                  }else{

                          iSatHi=(ISayHi)Class.forName("SayHiImp.SayHiEnImp").newInstance();

                  } 

                  }catch(Exception e){

                          System.out.println(e);

                  }

       }

 

       public ISayHi getSayHi()

       {

                  return iSatHi;

       }

}



XML解析类:



package XMLPrass;

import java.io.File;



import javax.xml.parsers.DocumentBuilder;

import javax.xml.parsers.DocumentBuilderFactory;



import org.w3c.dom.Document;

import org.w3c.dom.Element;

import org.w3c.dom.NodeList;



public class XmlPrass {

          private static XmlPrass xmlPrass=null;

 

          private XmlPrass(){}

 

          public String sax() {

                  String result="";

                  try{

                        DocumentBuilderFactory builderFactory=DocumentBuilderFactory.newInstance();

                        DocumentBuilder builder=builderFactory.newDocumentBuilder();

                        Document document=builder.parse(new File("src/MyXml.xml"));

                        Element element=document.getDocumentElement();

                        NodeList nl=element.getElementsByTagName("say-configuation");

                        result=nl.item(0).getAttributes().getNamedItem("src").getTextContent();

                        }catch(Exception e){

                               System.out.println(e);

                        }

                   return result;

          }

 

          public static XmlPrass newInstance(){

                      if(xmlPrass==null){

                              xmlPrass=new XmlPrass();

                      }

                      return xmlPrass;

          }

}



测试类:



package SayHiMain;



import SayHiController.Controller;



public class SayHi {



         /**

          * @param args

          */

         public static void main(String[] args) {

         Controller controller=new Controller();

         System.out.println(controller.getSayHi().SayHi("jack"));

         }

}



MyXml.xml



<?xml version="1.0" encoding="UTF-8"?>

<say>

	<say-configuation src="EN"/>

	<say-class name="ZH" class="SayHiImp.SayHiZhImp" />

	<say-class name="EN" class="SayHiImp.SayHiEnImp" />

</say>
xyghehehehe 2015-06-27
  • 打赏
  • 举报
回复
楼主可以不编译a、b、c下面的类,保持其仍然是文本文件,在pub类中提供方法,调用时指定不同的参数,使用字节码工具根据参数选择a、b、c下面的文本文件生成需要的类,并且将这些类使用不同的类加载器进行加载。a、b、c三个目录下的类分别对应三个类加载器。这样的话,a、b、c三个目录下实际上没有编译好的类,自然是隔离的。为了方便使用,最好是a、b、c下面的各个类都有一个统一的接口,这样调用pub获得的实例可以直接转换成这些接口的实例,直接使用。如果不想要这些统一的接口的话,也可以直接返回Object实例,然后通过反射去调用
whos2002110 2015-06-25
  • 打赏
  • 举报
回复
2楼就是正确答案, 说反射的怕都是让楼主“类多,屏蔽包”这些莫须有的需求给绕进去了。 洗洗睡了
0轰隆隆0 2015-06-25
  • 打赏
  • 举报
回复
引用 73 楼 ttjxtjx 的回复:
两种方式的代码区别不大,接口是肯定要用的,需要我可以把代码简化下贴出来
能否写一个简单的例子呢?
ttjxtjx 2015-03-31
  • 打赏
  • 举报
回复
两种方式的代码区别不大,接口是肯定要用的,需要我可以把代码简化下贴出来
0轰隆隆0 2015-03-27
  • 打赏
  • 举报
回复
回复 70楼 ttjxtjx 反射机制加代理类,我在上一贴中提到过,但是都没有实现,我也没有头绪。
ttjxtjx 2015-03-27
  • 打赏
  • 举报
回复
引用 71 楼 fulong258 的回复:
回复 70楼 ttjxtjx 反射机制加代理类,我在上一贴中提到过,但是都没有实现,我也没有头绪。
不用包隔离直接system classloader加载类,再返回Object Instance,再转接口使用就可以了。 之前那个带隔离实现也是想复杂了, 用那个package classloader加载类,再返回Object Instance,再转接口使用。 两种都不需要用到代理。。。。。。。。
ttjxtjx 2015-03-26
  • 打赏
  • 举报
回复
引用 68 楼 fulong258 的回复:
回复63楼 ttjxtjx 不用接口,是否有更好和简洁的办法!!!
你要求包与包隔离,那就必须使用ClassLoader,使用不同ClassLoader就一定要通过接口调用。 如果不要求隔离,用反射机制加代理类实现就很简单。这样的话不用接口,你使用的时候还得去考虑转换成哪个包下的类,不是更麻烦。接口是肯定要用的,毕竟面向接口编程好处是很多的
0轰隆隆0 2015-03-26
  • 打赏
  • 举报
回复
回复 67楼 ymwcwee 能否提供详细代码!!!
0轰隆隆0 2015-03-26
  • 打赏
  • 举报
回复
回复63楼 ttjxtjx 不用接口,是否有更好和简洁的办法!!!
咔啪咔啪 2015-03-12
  • 打赏
  • 举报
回复
接口似乎是不可避免了,因为动态加载后要调用方法总要确定是哪个包下的类,为了避免代码量,接口就出来了,不过A、B、C三个类倒是可以省略,或者把A、B、C转换成接口即可,Pub类增加个设置包的方法

package entity;

public class Pub {
	private String pkg = "a";
	public Pub(){
		
	}
	public void setPackage(String pkg){
		this.pkg = pkg;
	}
	public Object loadClass(String className){
		try {
			String selfPath = Pub.class.getPackage().getName();
			Class<?> clazz = Class.forName(selfPath+"."+this.pkg+"."+className);
			return clazz.newInstance();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}
}

ttjxtjx 2015-03-04
  • 打赏
  • 举报
回复
其实已有非常强大的框架能满足这个需求:OSGI 只是初略了解下,没真正用过。
ttjxtjx 2015-03-04
  • 打赏
  • 举报
回复
其实有非常强大框架可以满足楼主需求:OSGi 只是初略了解下,具体我也没用过。
SexyCode 2015-03-04
  • 打赏
  • 举报
回复
顶一个!期待大神出现
ttjxtjx 2015-03-04
  • 打赏
  • 举报
回复
不知道上面修改过之后是不是满足楼主要求呢。 隔离还是通过ClassLoader隔离,PUB只能通过接口来使用实现类,且A、B、C包相互不可见。 整包切换通过不同packageName的动态代理类(DynProxy),获得对应包下的代理对象(X1,X2,X3)。 假设A、B、C包下各自新增了一个实现类 class X4 implement IX4,不需要额外的编码PUB中直接可以通过已有代理类生成IX4的实例进行访问。如下

//访问A包下的新增的IX4实现,注意:这里一定要转接口,不能转为a.X4,因为a.X4对于PUB不可见
((IX4)a.getProxy("X4")).printX4();
之前代码有点问题,类加载器会多次加载同一个类,这里也简单的修改了一下PackageClassLoader
public class PackageClassLoader extends ClassLoader {
	private String packageName;
	private Map<String, Class> cache = new HashMap<>();

	public PackageClassLoader(String packageName) {
		super();
		this.packageName = packageName;
	}

	public PackageClassLoader(String packageName, ClassLoader parentLoader) {
		super(parentLoader);
		this.packageName = packageName;
	}

	protected java.lang.Class<?> findClass(String name)
			throws ClassNotFoundException {
		String fullClassName = packageName + "." + name;
		byte[] classData = getClassData(fullClassName);
		if (classData == null) {
			throw new ClassNotFoundException("class [" + fullClassName
					+ "] not found ");
		} else {
			if (cache.containsKey(fullClassName)) {
				return cache.get(fullClassName);
			} else {
				Class clazz = defineClass(fullClassName, classData, 0,
						classData.length);
				cache.put(fullClassName, clazz);
				return clazz;

			}
		}
	};

	private byte[] getClassData(String name) {
		try {
			InputStream is = new FileInputStream(rootClassName(name));
			ByteArrayOutputStream os = new ByteArrayOutputStream();
			int buffSize = 4096;
			byte[] buff = new byte[buffSize];
			int readNum = -1;
			while ((readNum = is.read(buff)) != -1) {
				os.write(buff, 0, readNum);
			}
			return os.toByteArray();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	private String rootClassName(String name) {
		return this.getParent().getResource("").getFile() + File.separator
				+ name.replace(".", File.separator) + ".class";
	}
}
ttjxtjx 2015-03-03
  • 打赏
  • 举报
回复
嫌IProxyImpl这个代理类大,改成动态代理就不大了。我简单的改了下。

DynProxy:
public class DynProxy implements InvocationHandler {

private String className;
private String packageName;
private ClassLoader loader;

public DynProxy(String packageName) {
super();
this.packageName = packageName;
this.loader = new PackageClassLoader(this.packageName);
}

@SuppressWarnings("rawtypes")
public Object getProxy(String className){
this.className = className;
try {
return Proxy.newProxyInstance(this.loader,
((Class) this.loader.loadClass(className)).getInterfaces(), this);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
return method.invoke(getInstance(className), args);
}

// 使用类加载器去寻找对应包下的类,再创建实例
@SuppressWarnings({"rawtypes" })
private Object getInstance(String className) {
try {
return ((Class) this.loader.loadClass(className)).newInstance();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}

}


main函数:
	public static void main(String[] args) {
DynProxy a = new DynProxy("com.bear.a");
DynProxy b = new DynProxy("com.bear.b");
DynProxy c = new DynProxy("com.bear.c");

((IX1)a.getProxy("X1")).printX1();
((IX1)b.getProxy("X1")).printX1();
((IX1)c.getProxy("X1")).printX1();
((IX2)a.getProxy("X2")).printX2();
((IX3)a.getProxy("X3")).printX3();
}


结果:


这样实现就算A、B、C包中新增了实现类也无须修改代理类了。
之前使用IProxyImpl是为了自由选择哪些接口需要暴露给PUB;改成DynProxy 也可以在调用getProxy的时候做限制。
0轰隆隆0 2015-02-26
  • 打赏
  • 举报
回复
skyhitnow: 在Spring和Hibernate中都有应用,但是如何将其抽取出来呢。 不必非得用接口实现,只要代码简洁完成功能(整包切换与隔离)即可。
0轰隆隆0 2015-02-26
  • 打赏
  • 举报
回复
回复 59楼 ttjxtjx 这样的思路前面已经有人提出了,但是并不是我想要的。因为a、b、c包下有大量的类,每个类里面有大量的方法。这样的话IProxyImpl 就太大了,不太适合。最后还是非常感谢ttjxtjx
朗晴 2015-02-13
  • 打赏
  • 举报
回复
楼主结贴子吧/。
ttjxtjx 2015-02-13
  • 打赏
  • 举报
回复
写了个例子不知道满不满足楼主的几点要求
目录结构


PUB类: 按我理解PUB应该是个工厂,生产A、B、C分别使用不同包中的实现。
public class PUB
{

public static void main( String[] args )
{
/**IProxy是暴露给外部的接口集合,这里是暴露了IX1,IX2,IX3接口
*a、b、c三个包中的类是使用单独的加载器加载的,而PUB和IProxyImpl是由系统类加载器加载,
*所以三个包中的实现对于PUB和IProxyImpl都是不可见的,他们只能看到接口看不到实现。
*不信的话你可以修改后面IProxyImpl代码,试试将object强转为接口(IX1) 改为强转成实现(X1),看看有什么结果
*/
IProxy A = new IProxyImpl("com.bear.a");
IProxy B = new IProxyImpl("com.bear.b");
IProxy C = new IProxyImpl("com.bear.c");
A.printX1();
B.printX2();
C.printX3();
}
}

IProxyImpl类:
/**
* IProxyImpl内部有一个类加载器,负责加载对应包下的类。
*
* 实现了IProxy接口集合IX1,IX2,IX3,这个类实际上是一个负责加载实现并调用的代理类
* @author Bear
*
*/
public class IProxyImpl implements IProxy
{

private String packageName;
private ClassLoader loader;

public IProxyImpl(String packageName)
{
super();
this.packageName = packageName;
loader = new PackageClassLoader(this.packageName);
}

@Override
public void printX1()
{
((IX1) this.getInstance("X1")).printX1();

}

@Override
public void printX2()
{
((IX2) this.getInstance("X2")).printX2();
}

@Override
public void printX3()
{
((IX3) this.getInstance("X3")).printX3();
}

//使用类加载器去寻找对应包下的类,再创建实例
private Object getInstance( String className )
{
try
{
return ((Class) loader.loadClass(className)).newInstance();
}
catch (ClassNotFoundException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (InstantiationException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IllegalAccessException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}

}

PackageClassLoader:
public class PackageClassLoader extends ClassLoader
{
private String packageName;

public PackageClassLoader(String packageName)
{
super();
this.packageName = packageName;
}

public PackageClassLoader(String packageName, ClassLoader parentLoader)
{
super(parentLoader);
this.packageName = packageName;
}

protected java.lang.Class<?> findClass( String name )
throws ClassNotFoundException
{
String fullClassName = packageName + "." + name;
byte[] classData = getClassData(fullClassName);
if (classData == null)
{
throw new ClassNotFoundException("class [" + fullClassName
+ "] not found " );
}
else
{
return defineClass(fullClassName, classData, 0, classData.length);
}
};

private byte[] getClassData( String name )
{
try
{
InputStream is = new FileInputStream(rootClassName(name) );
ByteArrayOutputStream os = new ByteArrayOutputStream();
int buffSize = 4096;
byte[] buff = new byte[buffSize];
int readNum = -1;
while ((readNum = is.read(buff)) != -1)
{
os.write(buff, 0, readNum);
}
return os.toByteArray();
}
catch (FileNotFoundException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}

private String rootClassName(String name)
{
return this.getParent().getResource("").getFile()+File.separator+name.replace(".",File.separator)+".class";
}
}

IProxy接口:
public interface IProxy extends IX1,IX2,IX3
{

}

IX1,IX2,IX3是三个接口,有各自的print方法分别由X1,X2,X3实现,代码就不用贴了吧。
运行结果:


有点类似tomcat加载多个web应用,有a、b、c三个web应用,内容完全一样只是项目根目录的名字不一样,tomcat加载三个web应用,abc各自不可见,根据URL确定调用哪个应用。
加载更多回复(55)

67,513

社区成员

发帖
与我相关
我的任务
社区描述
J2EE只是Java企业应用。我们需要一个跨J2SE/WEB/EJB的微容器,保护我们的业务核心组件(中间件),以延续它的生命力,而不是依赖J2SE/J2EE版本。
社区管理员
  • Java EE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧