黑马程序员---java动态代理与类加载器

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------


。 代理需要目标类与代理类实现同一个接口

>> 静态代理


<span style="font-size:14px;">	《代理类与被代理类的共同父接口》

package com.kingowe.staticproxy;
/**
 * 该接口为静态代理类与真实类共同的父接口
 * @author Administrator
 *
 */
public interface StaticProxyInterface {

	void show();	
}

	

	《被代理类(真实实现类)》

package com.kingowe.staticproxy;
/**
 * 该类为静态代理的真实实现类
 * @author Administrator
 *
 */
public class StaticProxyRealClass implements StaticProxyInterface {

	@Override
	public void show() {
		System.out.println("这是真实实现类:StaticProxyRealClass");
	}

}


	《代理类》

package com.kingowe.staticproxy;
/**
 * 该类为静态代理的代理类
 * @author Administrator
 *
 */
public class StaticProxyProxyClass implements StaticProxyInterface {

	StaticProxyRealClass realClass;
	
	public StaticProxyProxyClass(StaticProxyRealClass realClass){
		this.realClass = realClass;
	}
	
	@Override
	public void show() {
		System.out.println("这是真是实现类的代理类:StaticProxyProxyClass");
		this.realClass.show();	// 【调用 真实实现类中的方法】
	}

}


	《测试》

package com.kingowe.staticproxy;

public class StaticProxyTest {

	public static void main(String[] args){
		
		StaticProxyRealClass realClass = new StaticProxyRealClass();
		StaticProxyInterface proxy = new StaticProxyProxyClass(realClass);   // 【给代理类传入其代理的对象】
		proxy.show();	// 【这里调用的是代理类中的show()方法,在代理类中调用了被代理类的对应方法(真正实现的方法)】
	}
	
}</span>


>> 动态代理

。 要想实现动态代理机制,则需要 java.lang.reflect.InvocationHandler 接口 和 java.lang.reflect.Proxy 类的支持

<span style="font-size:14px;">public interface InvocationHandler{

	abstract Object  invoke(Object proxy, Method method, Object[] args) ;	

	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
	 *     Parameters
	 *	proxy:  the proxy instance on which the method was invoked 
	 *	method:  the method invoked on the proxy instance 
	 *	args:  an array of objects containing the parameters passed to the method, or null if
	 *		 no arguments are expected. Primitive types are boxed. 
	 *
	 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

}</span>
。 Proxy 类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类


   类中的方法:


public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler handler)


Parameter:
ClassLoader loader: 类加载器
Class<?>[] interfaces:得到全部的接口
InvocationHandler handler:得到InvocationHandler接口的子类实例


Returns:
a new proxy object that delegates(代表) to the handler h



>> 类加载器


。 在 java 中有以下三种类加载器

· BootStrap ClassLoader:此加载器采用C++编写,一般开发中看不到(BootStrap---->JRE/lib/rt.jar)

· Extension ClassLoader:用来进行扩展类的加载,一般对应的是 %JAVA_HOME%/jre/lib/ext 目录(在开发中,一般需要一些扩展
的jar包中的类,这些包将被导入到该目录下) 中的类,这个目录中的类由 该加载器加载(ExtClassLoader---->JRE/lib/ext/*.jar)


· APPClassLoader: 加载classpath 指定的类,是最常用的一种加载器(AppClassLoader----->CLASSPATH指定的所有jar或目录。)


    通过 Class 类可以得到当前类的类加载器


>> 使用类加载器加载资源文件

。 比如程序需要一个配置文件,则将该配置文件放在程序对应的 .class 文件同级目录下(或在该目录下新建一个resource文件夹):

有一个类:com.kingowe.test.ClassName,要加载的配置文件 conf.prop(放在ClassName.class同级目录下):
InputStream is = ClassName.class.getClassLoader().getResourceAsStream("com/kingowe/test/conf.prop");
// 【注意路径写法,最前边不加 "/", getResourceAsStream()方法会查找classpath对应的所有目录 】
// 如果配置文件(资源)放在 .class 同级目录下的resource 目录下,则路径的写法:resource/com/kingowe/test/conf.pro


>> 类加载器的委托机制(加载类的流程)

。 类加载器父子关系:

父->子: BootStrap -> ExtClassLoader -> AppClassLoader -> 自定义类加载器

。 当java虚拟机要加载一个类时,到底使用哪个类加载器加载呢?

· 首先,当前线程的类加载器去加载线程中的第一个类
· 如果类A中引用了类B,java虚拟机将使用加载类A的加载器加载类B,
· 还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类

     每个类加载器加载类时,又先委托给其上级类加载器


· 当所有的父类加载器没有加载到类,回到发起者类加载器(不会再向下找了),如果还无法加载,则抛出 ClassNotFoundException

     所以有面试题:可不可以自己写一个类"java.lang.System"?

答:通常情况下不可以,因为类加载器的委托机制,对于自己写的类,会先从BootStrap开始查找加载,而在 BootStrap 加载自己
     管辖范围的类(JRE/lib/rt.jar) 时,在该jar包下有 java.lang.System 类,所以会在此处会成功加载一个java.lang.System类,
     并不会加载到自己写的java.lang.System类

<span style="font-size:14px;"><示例代码(动态代理)2:>

	《接口》

public interface Hello {  
  
    void sayHello(String to);  
    
    void print(String p);   
   
}  

	《接口的真实实现类》

public class HelloImpl implements Hello {  
      
    public void sayHello(String to) {  
        System.out.println("Say hello to " + to);  
    }  
      
    public void print(String s) {  
        System.out.println("print : " + s);  
    }  
      
}  



	《与代理类相关联的InvocationHandler类》

public class LogHandler implements InvocationHandler {  
      
    private Object dele;  
      
    public LogHandler(Object obj) {  
        this.dele = obj;  
    }  
      
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
        doBefore();  
        //在这里完全可以把下面这句注释掉,而做一些其它的事情  
        Object result = method.invoke(dele, args);  
        after();  
        return result;  
    }  
      
    private void doBefore() {  
        System.out.println("before....");  
    }  
      
    private void after() {  
        System.out.println("after....");  
    }  
} 


	《测试类》

public class ProxyTest {  
  
    public static void main(String[] args) {  

        HelloImpl impl = new HelloImpl();  	// 【被代理类(真实实现类)】
        LogHandler handler = new LogHandler(impl);   // 【】
 
        /*【 这里把handler与impl新生成的代理类相关联,第二个参数为被代理类实现的所有接口,因为代理类与被代理
	类需要是实现相同的接口,所以需要传入该参数 】 */

        Hello hello = (Hello) Proxy.newProxyInstance(
			impl.getClass().getClassLoader(), 
			impl.getClass().getInterfaces(), 
			handler);  
          
        //【 这里无论访问哪个方法,都是会把请求转发到handler.invoke() 】
        hello.print("All the test");  
        hello.sayHello("Denny");  
    }  
  
} </span>
输出:
before....  
print : All the test  
after....  
before....  
Say hello to Denny  
after....  


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值