java之 类的加载及动态代理

------- android培训java培训、期待与您交流! ----------

Java中的类都是为类加载器加载的,java中有三个主要的类加载器:Boot Strap ,ExtClassLoader,AppClassLoader。java的类加载器也是类,那么必须要有一个不是类的类加载器,加载类加载器。那么这个类加载器就是Boot Strap。

java中的类加载器具有子父关系的树形结构进行组织。


类加载器的委托机制:

首先当需要加载一个类A时,在不指定加载器的情况下,会先用当前线程的类加载器进行加载,当其它类例如类B用到了这个类A时,这个类B也用类A的加载器进行加载。

在加载器加载类的同时,又先委托给上级,也就是加载类A的加载器在加载时先让它的上级去加载,上级再交给上级,当到BootStrap时就会开始查找这个类,如果找不到会一次

委托给下级查找,找到了就加载找不到就继续传递下级,当传递到加载类A的加载器时,如果找到了这个类A那么就加载,找不到就报出异常。

当我们通过ClassLoader.loadClass方法指定加载器时,也遵循委托机制,也就是这个指定的类加载器也会委托给上级至BootStrap依次开始查找和加载。

当我们定义一个类加载器时,首先需要继承ClassLoader类。

其次,我们只需要重写findClass()方法,不需要重写loadClass()方法,因此loadClass方法其实就是累加器委托机制的实现方法,

类加载器会掉用这个方法委托给所有上级去加载,只有当没有加载到时才会掉用自定义加载器的findClass()方法。

findClass方法内部,需要我们定义字节读取流,和一个byte数组,因为在这个方法的内部我们需要调用defineClass()方法,通过此方法将字节数组转变成Class

自定义一个普通的类加载器:

package ClassLoader_day1;


import java.util.Date;


public class MyClassLoaderRecourse extends Date{
}

package ClassLoader_day1;


import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.InputStream;


public class MyClassLoader extends ClassLoader{
String classPath="E:\\黑马学习\\类加载器\\bin\\ClassLoader_day1";
//我们只需要重写findClass方法
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try{
String fileName=classPath+"\\"+name+".class";
System.out.println(fileName);
FileInputStream is=new FileInputStream(fileName);
ByteArrayOutputStream bis=new ByteArrayOutputStream();
System.out.println(fileName);
int len=0;
while((len=is.read())!=-1){
bis.write(len);
}
byte[] arr=bis.toByteArray();
System.out.println("xxxx");
return defineClass(arr,0,arr.length);
}
catch(Exception e){}

return super.findClass(name);
}

}

package ClassLoader_day1;
import java.util.Date;
public class MyClassLoaderTest1 {
public static void main(String[] args)throws Exception{
MyClassLoader cla=new MyClassLoader();
System.out.println("xxx");
Class cla1=cla.loadClass("MyClassLoaderRecourse");
System.out.println(cla1.getName());
Date mr=(Date)cla1.newInstance();
//MyClassLoaderRecourse mr=(MyClassLoaderRecourse)cla1.newInstance();
System.out.println(mr);
System.out.println(mr.getClass().getClassLoader().getClass().getName());
}
}

结果为:

ClassLoader_day1.MyClassLoaderRecourse
Mon Nov 24 00:01:48 CST 2014
ClassLoader_day1.MyClassLoader

通过学习类加载器想到了在连接SqlServer数据库是要用到Class.forName()方法,这句代码的意思就是加载com.microsoft.sqlserver.jdbc.SQLServerDriver这个类吧。

用上面的自定义类加载器改了路径,换到sqljdbc4.jar的路径下,就成功的读取到了数据库中的内容。

package ClassLoader_day1;
import java.sql.*;
public class test {
Connection ct=null;
ResultSet rs=null;
PreparedStatement ps=null;
public static void main(String[] args){
test one=new test();
}
public test(){
String na="sa";
String mm="qichang";
String qudong="com.microsoft.sqlserver.jdbc.SQLServerDriver";
String fuwu="jdbc:sqlserver://2012-20111117YN:1433;DatabaseName=company";
try{
//Class.forName(qudong);

//用自定义的加载器加载驱动。

new MyClassLoader().loadClass(qudong);

ct=DriverManager.getConnection(fuwu,na,mm);
ps=ct.prepareStatement("select * from bumen where zhanghao=?");
ps.setString(1,"zh101");
System.out.println("haole");
rs=ps.executeQuery();
while(rs.next()){
String zhanghao=rs.getString(1);
String mima=rs.getString(2);
System.out.println(zhanghao+"'''"+mima);
}

}
catch(Exception e){
System.out.println(e.toString());
}

finally{
try{
if(ct!=null){
ct.close();
}if(ps!=null){
ps.close();
}if(rs!=null){
rs.close();
}
}
catch(Exception e){
System.out.println(e.toString());
}
}
}
}

JDK动态代理:
 交叉业务的编程问题即为AOP(Aspect onented program)面向方面的编程就是为了使交叉业务模块化。
什么是交叉业务?我的理解为:例如:有一个A类有个方法info B类也有个 info方法 C类有个 show方法。
当我们需要将这些方法的功能进行计算运行时间,异常处理,日志,等操作时,我们不可能更改所有类中的方法。
那么我们就需要使用AOP代理。动态代理的实现需要将这些类,实现一个或者多个接口。通过接口在运行时动态的生成class。
那么生成的代理类实例就可以当做这个接口的任何实例来用,当我们使用这些类的方法时,就会先走这个代理Proxy实例。
由它 通过给定的invocationHandler来具体操作。invocationHandler内部只有一个方法就是invoke方法,它内部使用method的invoke方法调用被代理类的方法
我们就可以再这句代码前后实现代码的附加。

生成动态代理类一般需要两个类:
(1). Interface InvocationHandler:
该接口中仅定义了一个方法
Object:invoke(Object obj,Method method, Object[] args)。
在实际使用时,第一个参数obj一般是指代理类,method是被代理类的方法
参数为:这个方法的参数。

这个借口的实现子类是具体操作被代理类是通过method的invoke方法实现操作,并在invoke方法前后等位置,实现额外语句。

(2).Proxy:该类即为动态代理类
 Proxy(InvocationHandler h):构造函数,估计用于给内部的h赋值。
Static Class getProxyClass (ClassLoader loader, Class[] interfaces):
获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组。
Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):
返回代理类的一个实例,返回后的代理类可以当作被代理
定义一个借口:

public interface Animal {
public abstract void run();
public abstract void eat();
}

public class Dog implements Animal {//需要被代理的类:目标类
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("狗奔跑迅速");
}
@Override
public void eat() {
// TODO Auto-generated method stub
System.out.println("狗吃骨头");
}
}

public class Recource {//此类为建议类。
public void method_1(){
System.out.println("额外语句1");
}
public void method_2(){
System.out.println("额外语句2");
}
}

public class MyProxy2 {
public static void main(String[] args){
final Recource rs=new Recource();//因为需要被内部类访问所以final
final Animal target=new Dog();
Animal al=(Animal)getProxy(rs, target);
al.eat();
al.run();
}
private static Object getProxy(final Recource rs, final Object target) {
Object obj=Proxy.newProxyInstance(
target.getClass().getClassLoader(), 
target.getClass().getInterfaces(), 
new InvocationHandler(){//匿名内部累的方式实现IvocationHandler接口
@Override
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
// TODO Auto-generated method stub
rs.method_1();
Object result=method.invoke(target, args);//参数为被代理类,及其方法的参数
rs.method_2();
return result;
}
});
return obj;
}
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值