--------------------- android培训、java培训、java学习型技术博客、期待与您交流! ----------------------
类加载器:加载类的工具,
一个类中出现了一个类的名字,java虚拟机首先把该类的字节码加载进内存,
Java虚拟机可以安装多个类加载器,每个加载器加载不同位置的类,一般用到的类加载器有三个bootstrap,extclassloader,appclassloader
类加载器也是java类,也是靠别的类加载器(bootstrap)加载bootstrap是嵌套在java虚拟机内核里面
范围
Boot
Ext:
App:classpath指定的jar或目录
//得到类加载器的类
System.out.println(ClassLoaderTest.class.getClassLoader().getClass().getName());
//system类是由C写的类加载器加载的
System.out.println(System.class.getClassLoader());
/**
* 类加载器的树状结构
* boot
* |--ext
* |--app
*/
ClassLoader loader = ClassLoaderTest.class.getClassLoader();
while(loader != null)
{
System.out.println(loader.getClass().getName());
loader = loader.getParent();
}
System.out.println(loader);
如果两个类加载器都可以加载同一个类文件,则有父级加载这是类加载器的委托机制
首先派当前线程的类加载器去加载第一个类
如果类A中引用了B类,则该类加载器继续加载
还可以通过ClassLoader.loadClass()方法去加载
先向上级类推脱,一直推脱到Boot,然后各个类加载器在自己的范围内查找,如果能找到则下级就不再寻找直接用,这样可以避免一个类被多次加载
自己写一个类加载器加载java.lang.System
编写自己的类加载器
模板方法设计模式:父类有一个方法,不管哪个子类,
首先自定义一个类加载器,继承app,指定加载路径
继承classloader
通过loadclass方法让父类去加载该类文件,如果加载不了则自己加载(该流程固定,但是细节由子类完成)
重写findclass方法
调用define方法返回class字节码
Tomcat启动之后,java虚拟机中会有很多的类加载器
Tomcat是由java虚拟机启动的
代理
代理类的每个方法与目标类的方法一样,而且代理类的方法必须去调用目标类的方法然后再加上自己的功能,
面向切面编程AOP
将交叉业务模块化
Java虚拟机可以再运行期间动态生成类的字节码文件,这种动态生成的类往往被用作代理类,即动态代理类
生成的动态代理类必须继承一个或多个接口,所以动态代理类只能用作具有相同接口的类的目标类的代理
Cglib可以动态生成一个类的子类,该子类也可以用作代理类
添加系统功能代码的位置
调用方法之前
调用方法之后
调用方法前后
Catch块中
单线程用stringbuilder
多线程用stringbuffer
让java虚拟机创建动态类及实例对象需要提供的信息
生成的类有哪些方法,通过让其实现的哪些接口的方式进行告知
产生的类字节码必须有一个关联的类加载器对象
生成的类中的方法时怎么样的也得由我们提供,把我们写的代码
或者通过newProxyInstance一步到位
publicclass test01 {
/**
* @param args
*/
publicstaticvoid main(String[] args) {
Class clazz = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
Constructor[] method = clazz.getConstructors();
StringBuilder sb = new StringBuilder(clazz.getName());
for(Constructor m : method)
{
//sb.append(c.getName());
Class[] parm = m.getParameterTypes();
for(Class cla : parm)
{
sb.append(cla.getSimpleName());
}
System.out.println(sb.toString());
}
try {
//创建一个构造器对象传递的参数为该构造参数的类字节码
Constructor c =clazz.getConstructor(InvocationHandler.class);
//创建对象
Collection coll = (Collection)c.newInstance(new myInvocationHandler());
System.out.println(coll.toString());
coll.clear();//清除集合
} catch (Exception e) {
e.printStackTrace();
}
}
}
class myInvocationHandler implements InvocationHandler
{
@Override
public Object invoke(Object arg0, Method arg1, Object[] arg2)
throws Throwable {
returnnull;
}
}
原理:
调用invoke方法涉及的三个要素:调用哪个对象,调用对象的哪个方法,方法的参数
AOP:作用的目标和将要执行的代码可以作为对象传递进去