----------android培训、java培训、java学习型技术博客、期待与您交流! -----------
1,类加载器
类加载器的作用:把字节码文件从硬盘上加载进内存来,并做一些处理之后,这些硬盘的字节码文件就变成了内存字节码。
类加载器的类别:Bootstrap(c++),ExtClassLoader 和 AppClassLoader(java)
[1]. Bootstrap
名称:引导类加载器
位置:最高父级类加载器
管辖范围:负责加载Java的核心类库中的类 被打包到Java的jdk安装目录的子目录jre/lib/rt.jar
【注意】包括ExtClassLoader和AppClassLoader类
[2]. ExtClassLoader类加载器
名称:扩展类加载器
位置:Bootstrap类的直接子类
管辖范围:负责加载打包到Java的jdk安装目录的子目录jre/ext/下面所有的jar包
[3]. AppClassLoader类加载器
名称:系统类加载器
位置:ExtClassLoader类的直接子类
管辖范围:负责加载系统环境变量ClASSPATH指定目录中所有的JAR包
类加载器的逆向查找:
class TestII{
public static void main(String[] args) throws Exception {
ClassLoader claaaloader = PropertyTest.class.getClassLoader();
while(null != claaaloader){
System.out.println(claaaloader);
claaaloader = claaaloader.getParent();
}
}
}
验证结果:
补充:Bootstrap不是用java语言写的,所以不会打印出。
2,类加载器委托机制
当需要某个类加载器要加载指定的类的时候,并不是立刻到自己的管辖范围去加载指定的字节码文件,而是将这个指定的类传递给父类,由父类尝试去到自己的加载范围去加载这个类。就这样,一级级地向上递推到类加载器的最高父类:JVM的内嵌类加载器---Bootstrap类加载器
Bootstrap类加载器首先在自己的管辖范围jre/lib/rt.jar中找到了指定类名对应的字节码文件。
如果找到相应的字节码文件就直接加载进来,结束本次对指定类的加载。
如果没找到,Bootstrap按照原路返回到ExtClassLoader,将这个要加载的指定类型交给ExtClassLoader去加载。
如果还没找到,就这样一级级向子类类加载器递推。如果在中间的某一级的类加载器找到了指定的类的字节码文件,就结束这次对指定类的加载。
如果退回到最初要加载类的类加载器的时候,并且在这个类加载器本身的管辖范围内还是没有找到这个指定的类的字节码文件,就会直接抛出ClassNotFoundException这个异常。
总结: 由某个子类加载器层层向上推进到Bootstrap类加载器加载。若最高父类类加载器无法加载指定的类,又开始层层向下递推到子类加载器进行加载。如果退回到发起者的类加载器还是没有办法加载指定的类,就抛出ClassNotFoundException这个异常。
3,代理的作用与功能
代理类和目标类的关系
代理类的功能与目标类的功能一样
只是在执行目标类相关功能的前或者后增加了新的辅助功能。
代理类的每个方法名与目标类的每个方法名都一样
代理类的每个方法都要调用目标类的每个方法
代理类的每个方法在调用目标类的每个方法的前或者后都会加上系统的额外功能
客户端不直接使用目标类,而是直接使用代理类,代理类实际上是在调用目标类的功能。
interface salecomputer{
void sale();
}
class producer implements salecomputer{
public void sale(){
System.out.println("sale a computer");
}
}
class Proxysale implements salecomputer{
private salecomputer sale;
public Proxysale(salecomputer sale) {
super();
this.sale = sale;
}
@Override
public void sale() {
// TODO Auto-generated method stub
System.out.println("proxy begin sale......");
sale.sale();
System.out.println("proxy end sale......");
}
public static void main(String[] args) {
salecomputer sale = new producer();
sale.sale();
System.out.println("use proxy.....");
salecomputer proxysale = new Proxysale(new producer());
proxysale.sale();
}
}
验证结果:
4,AOP技术
AOP:面向切面编程。主要是处理一些交叉业务。
如果将切面的代码移到原始方法的周围,原始方法看做目标类的方法,那么移动以后的切面代码+原始代码就是代理类对应的方法
代理技术的分类:
静态代理类: 就是手动为每一个目标类的每一个方法都增加交叉业务,也就是手动为每一个目标类增加代理类
缺点:如果目标类数量非常多或者目标类中的功能非常多,直接使用静态代理的方式来为目标类增加交叉业务会非常的繁琐。
动态代理类:通过特定的设置,在程序运行期间指示JVM动态地生成类的字节码。这种动态生成的类往往被用作代理类,即动态代理类
实现方式:使用JVM生成动态代理类,不过需要实现被代理类的实现接口
使用第三方库CGLIB:目标类没有实现相应的接口,又需要为这个类动态生成代理类,CGLIB可以为目标类动态生成目标类的子类,
并把这个动态生成的子类作为这个类的代理类
5,通过反射创建动态代理
a,方法一
public static void main(String[] args) throws IntrospectionException, Exception, NoSuchMethodException {
Class clazz = Proxy.getProxyClass(ArrayList.class.getClassLoader(), List.class);
Constructor constructor = clazz.getConstructor(InvocationHandler.class);
Object proxyobj = constructor.newInstance(new InvocationHandler(){
List target = new ArrayList();
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
return method.invoke(target, args);
}
});
System.out.println(proxyobj.getClass());
}
验证结果:
b,方式二:将前两步合二为一
Class[] interfacea = {List.class};
Object proxyobj2 = Proxy.newProxyInstance(
List.class.getClassLoader(),
interfacea,
new InvocationHandler() {
List target = new ArrayList();
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
return method.invoke(target, args);
}
});
System.out.println(proxyobj2.getClass());
验证结果:
总结:这种方式就可以很好的创建一个动态代理了。但是用Object接收被代理的引用,那么对应的方法就没有办法使用了。
6,目标类和系统功能的参数化使用
主要生成带有通告的代码:
public class IntroSpectorDemo {
public static void main(String[] args) throws IntrospectionException, Exception, NoSuchMethodException {
List target = new ArrayList();
Advice advice = new MyAdvice();
List proxyobj2 = (List)getInstance(target,advice);
proxyobj2.add("abc");
System.out.println("********************");
proxyobj2.size();
}
public static Object getInstance(final List target,final Advice Advice) {
Object proxyobj2 = Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
Advice.beforeMethod(target, method, args);
Object retval = method.invoke(target, args);
Advice.afeterMethod(target, method, args);
return retval;
}
});
return proxyobj2;
}
}
Advice实现类:
public class MyAdvice implements Advice{
private long beginTime;
private long endTime;
@Override
public void beforeMethod(Object target, Method method, Object[] args) {
// TODO Auto-generated method stub
System.out.println("到黑马学习啦!");
beginTime =System.currentTimeMillis();
}
@Override
public void afeterMethod(Object target, Method method, Object[] args) {
// TODO Auto-generated method stub
System.out.println("从黑马马上毕业了!");
endTime =System.currentTimeMillis();
System.out.println(method.getName() +" using "+ (endTime -beginTime)/1000+ "s");
}
}
Advice接口:
public interface Advice {
//目标代码之前的交叉业务
public void beforeMethod(Object target, Method method, Object[] args);
//目标代码之后的交叉业务
public void afeterMethod(Object target, Method method, Object[] args);
}
验证结果: