------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....