44.类加载器及其委托机制的深入分析
程序出现类,类加载器就要这个类class文件加载到内存中并处理得到了字节码
java虚拟机中可以安装多个加载器,系统默认三个主要加载器,每个负责特定位置的类:bootStrap,extclassloader,appclassloader。
类加载器也是java类,其也要被类加载器加载,显然必须有第一个加载器不是java类,这正是bootStrap
java虚拟机中的所有类加载器采用具有父子关系的树形结构进行组织,在实例化每个来加载器对象时,需要为其指定一个父级类加载器对象或默认采用系统类加载器为其类加载器加载。
每个类加载器加载类时,要先委托给其上级类加载器。
如果自己写类加载器,并且希望不让他委托给其上级类加载器加载,需要特殊编写
45.自定义类加载器的编写原理分析
首先继承抽象classloader类,编写覆盖findclass方法
调用这个加载器类是通过loadclass方法加载想要加载的类。
模板方法设计模式:
父类->loadClass/findClass/得到class文件转成字节码-
>definClass()
46.编写对class文件进行加密的工具类
String srcPath = args[0];
String destDir = args[1];
FileInputStream fis = new FileInputStream(srcPath);
String destFileName = srcPath.substring(srcPath.lastIndexOf('//')+1);
String destPath = destDir + "//" + destFileName;
FileOutputStream fos = new FileOutputStream(destPath);
cypher(fis,fos);
fis.close();
fos.close();
}
private static void cypher(InputStream ips ,OutputStream ops) throws Exception{
int b = -1;
while((b=ips.read())!=-1){
ops.write(b ^ 0xff);
}
}
47.编写和测试自己编写的解密类加载器
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String classFileName = classDir + "//"
+ name.substring(name.lastIndexOf('.')+1) + ".class";
try {
FileInputStream fis = new FileInputStream(classFileName);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
cypher(fis,bos);
fis.close();
System.out.println("aaa");
byte[] bytes = bos.toByteArray();
return defineClass(bytes, 0, bytes.length);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
调用:
Class clazz = new MyClassLoader("itcastlib").loadClass
("cn.itcast.day2.ClassLoaderAttachment");
Date d1 = (Date)clazz.newInstance();
System.out.println(d1);
48.类加载器的一个高级问题的实验分析
==========第9单元:动态代理技术的深入讲解==============
49.分析代理类的作用与原理及AOP概念
编写一个与目标类具有相同接口的代理类,代理类的每个方法调用目标类的相同方法,并在调用方法时加上系统功能代码。
在配置文件中配置是使用目标类还是代理类,这样以后很容易切换,譬如,想要日志功能时就配置代理类,否则配置目标类,这样增加系统功能很容易,运行一段时间后,想去掉系统功能也很容易。
AOP(aspect oriented program)面向方面的编程
aop的目标就是使交叉业务模块化,这正好使用代理技术解决
要为系统各种接口的类增加代理功能,那将需要很多代理类,如果都是用静态代理方式很麻烦,所以应用jvm动态生成的类就很好了。
jvm在运行期间动态生成出类的字节码,这种动态生成的类往往被用做代理类,即动态代理类。
jvm生成的动态类必须实现一个或多个接口,所以jvm生成的动态类只能用作具有相同接口的目标类的代理。如果目标类没有实现接口的功能,那么怎么告诉jvm也生成跟目标类定义的方法,jvm没办法,只能通过第三方库
CGLIB库可以动态生成一个类的子类,一个类的子类也可以用作该类的代理,所以,如果要为没有实现接口的类生成动态代理类,那么可以使用CGLIB库。
代理类的各个方法除了调用目标的相应方法和对外返回目标返回的结果外,还可以在代理方法中的四个位置加上系统功能代码:
1在调用目标方法之前
2在调用目标方法之后
3在调用目标方法前后都有
4在处理目标方法异常的catch块中
50.创建动态类及查看其方法列表信息
StringBuilde与StringBuffer的区别:StringBuilder用在单线程,StringBuffer用在多线程,因为他要考虑安全因素
Class clazzProxy1 = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
System.out.println(clazzProxy1.getName());
System.out.println("----------begin constructors list----------");
Constructor[] constructors = clazzProxy1.getConstructors();
for(Constructor constructor : constructors){
String name = constructor.getName();
StringBuilder sBuilder = new StringBuilder(name);
sBuilder.append('(');
Class[] clazzParams = constructor.getParameterTypes();
for(Class clazzParam : clazzParams){
sBuilder.append(clazzParam.getName()).append(',');
}
if(clazzParams!=null && clazzParams.length != 0)
sBuilder.deleteCharAt(sBuilder.length()-1);
sBuilder.append(')');
System.out.println(sBuilder.toString());
}
51.创建动态类的实例对象及调用其方法
Constructor constructor = clazzProxy1.getConstructor(InvocationHandler.class);
class MyInvocationHander1 implements InvocationHandler{
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
return null;
}
}
Collection proxy1 = (Collection)constructor.newInstance(new MyInvocationHander1());
System.out.println(proxy1);
proxy1.clear();
52.完成InvocationHandler对象的内部功能
Object proxy3 = Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler(){
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
long beginTime = System.currentTimeMillis();
Object retVal = method.invoke(target, args);
long endTime = System.currentTimeMillis();
System.out.println(method.getName() + " running time of " + (endTime - beginTime));
return retVal;