自定义ClassLoader在 Web环境下的问题

笑面书生 发布于 2013/07/13 10:11
阅读 1K+
收藏 2

尝试通过自定义ClassLoader 配和 ASM实现AOP.


package com.hkliang.core.web;

public class WebClassLoader extends ClassLoader{
	
    public WebClassLoader(){
        super(WebClassLoader.class.getClassLoader());
    }
	
    public Class<?> defineClass(String name, byte[] code) throws ClassNotFoundException{
        return defineClass(name, code, 0, code.length );
    }
}
在Servlet中



@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
    WebClassLoader webClassLoader = new WebClassLoader();
		
    String className = "com.hkliang.core.aop.asm.Test";
    try {		
        Class test = webClassLoader.defineClass(className, PrintClass.getBytesFromBasePath(className));
        ClassLoader cl  =  test.getClassLoader();
        System.out.println( "Test is loader by "   +  cl);
        while  (cl  !=   null ) {
            cl  =  cl.getParent();
            System.out.println(cl);
        }
            
        Test t = (Test)test.newInstance();
            
    } catch (ClassNotFoundException e1) {
        e1.printStackTrace();
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
}
异常信息为



INFO: Server startup in 8967 ms
test is  com.hkliang.core.web.WebClassLoader@5eaecb
WebappClassLoader
  context: 
  delegate: false
  repository: /WEB-INF/classes/
----------> Parent Classloader:
java.net.URLClassLoader@438d57

java.net.URLClassLoader@438d57
sun.misc.Launcher$AppClassLoader@167198e
sun.misc.Launcher$ExtClassLoader@1beea90
null
七月 13, 2013 1:17:37 上午 org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [com.hkliang.project.controller.ProjectController] in context with path [] threw exception
java.lang.ClassCastException: com.hkliang.core.aop.asm.Test cannot be cast to com.hkliang.core.aop.asm.Test
	at com.hkliang.project.controller.ProjectController.doGet(ProjectController.java:47)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:83)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:223)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:107)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:474)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:155)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:75)
	at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:933)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:90)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:493)
	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:986)
	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:625)
	at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:223)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1584)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1543)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
	at java.lang.Threakkdd.run(Thread.java:722)
问题:Servlet中声明的Test与自定义ClassLoader加载的Test不是在同一个ClassLoader中,如何实现自定义ClassLoader通过加载 byte[]类型的字节码,并委托给父加载器进行加载呢,实现AOP的目标呢?


加载中
0
笑面书生
笑面书生

自己顶一下,怎么没有加答,指点一二,是思路有问题吗?

0
陈老师1
陈老师1

两个没有上下级关系的不同的classLoader之间没法通用class的实例。即使有上下级关系的classloader上级也是没法访问下级。

没用过asm对它内部怎么创建类实例不清楚,不过看起来跟当前servlet中使用的classloader应该是不同的,甚至有可能级别也不同。

笑面书生
笑面书生
有下上及关系呀,我自定义的WebClassLoader的parent是Tomcat的WebappClassLoade
0
笑面书生
笑面书生
要沉吗。。。
0
笑面书生
笑面书生

自己解决了,看一下 ClassLoader的源码:

protected final Class<?> defineClass(String name, byte[] b, int off, int len)
        throws ClassFormatError
    {
        return defineClass(name, b, off, len, null);
    }
defineClass 为 final,就是子类不能重写

自定议的ClassLoader使用反射方式:

public class WebClassLoader extends ClassLoader {

	public WebClassLoader() {
		super(WebClassLoader.class.getClassLoader());
	}
	
	public Class<?> defineClass(String name, byte[] code)
			throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		ClassLoader loader = getParent();
		Class<?> cls = ClassLoader.class;
		Method method = cls.getDeclaredMethod(
			"defineClass", new Class[] { String.class, byte[].class,int.class, int.class });
		method.setAccessible(true);
		Object[] args = new Object[] {name, code, new Integer(0), new Integer(code.length) };
		Class clazz = (Class<?>) method.invoke(loader, args);
		try {
			clazz.newInstance();
		} catch (InstantiationException e) {
			e.printStackTrace();
		}
		return clazz;
	}

	@Override
	public Class<?> loadClass(String name) throws ClassNotFoundException {
		return getParent().loadClass(name);
	}
}
就实现了,有了这个基础 配合使用Classworing工具箱(我尝试使用的是ASM)即可以开发 AOP 、IOC框架了

@陈老师apusic

陈老师1
陈老师1
恩,恭喜! 这个问题告诉我们,有时候问题的原因也许真的不在我们这里
返回顶部
顶部