`

黑马程序员_java高新(四)_类加载器、动态代理

 
阅读更多

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

 

类加载器:

 

 

类加载器就是加载类的工具。

 

 

Java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:

 

 

BootStrap,   

 

ExtClassLoader,   

 

AppClassLoader

 

 

类加载器也是Java类,因为其他是java类的类加载器本身也要被类加载器加载,显然必须有第一个类加载器不

 

 

java类,就是BootStrap

 

 



 

 

 

类加载器的委托机制:

 

 

加载过程:

 

 

1、首先当前线程的类加载器去加载线程中的第一个类。

 


2、如果类A中引用了类B,Java虚拟机将使用加载类A的类装载器来加载类B。

 

 

3、还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类。

 

 

4、每个类加载器加载类时,又先委托给其上级类加载器。

 

 

自定义一个类加载器:

 

public class MyClassLoader extends ClassLoader {

	public static void main(String[] args) throws Exception {

		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);
		}
	}

	private String classDir;

	//重写findClass方法
	@Override
	protected Class<?> findClass(String name) throws ClassNotFoundException {

		String classFileName = classDir + "\\" + name + ".class";
		FileInputStream fis = null;
		try {
			fis = new FileInputStream(classFileName);
			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			cypher(fis,bos);
			fis.close();
			byte[] bytes = bos.toByteArray();
			return defineClass(bytes,0,bytes.length);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return super.findClass(name);
	}
	
	public MyClassLoader() {
		
	}
	
	public MyClassLoader(String classDir) {
		
		this.classDir = classDir;
	}
	
}

 

 

-----------------------------------------------------------------------------------------

 

 

动态代理:

 

 

AOP(面向切面编程):

 

 

系统中存在交叉业务,一个交叉业务就是要切入到系统中的一个方面,如下所示:

 

 

                                    安全      事务         日志

StudentService  ------|----------|------------|-------------

 

CourseService   ------|----------|------------|-------------

 

MiscService     ------|----------|------------|-------------

 

 

 

用具体的程序代码描述交叉业务:

 

 

method1         method2          method3

{                        {                           {

------------------------------------------------------切面

....            ....              ......

------------------------------------------------------切面

}                          }                           }

 

 

 

交叉业务的编程问题即为面向方面的编程(Aspect oriented program ,简称AOP),AOP的目标就是要使交叉业

 

 

务模块化。可以采用将切面代码移动到原始方法的周围,这与直接在方法中编写切面代码的运行效果是一样

 

 

的,如下所示:

 

 

 

------------------------------------------------------切面

func1         func2            func3

{                   {                     {

....            ....              ......

}                    }                     }

------------------------------------------------------切面

 

 

 

使用代理技术正好可以解决这种问题,代理是实现AOP功能的核心和关键技术。

 

 

JVM可以在运行期动态生成出类的字节码,这种动态生成的类往往被用作代理类,即动态代理类。

 

 

JVM生成的动态类必须实现一个或多个接口,所以,JVM生成的动态类只能用作具有相同接口的目标类的代理。

 

 

CGLIB库可以动态生成一个类的子类,一个类的子类也可以用作该类的代理,所以,如果要为一个没有实现

 

 

接口的类生成动态代理类,那么可以使用CGLIB库。

 

 

创建动态类的实例对象过程:

 


1、用反射获得构造方法

 


2、编写一个最简单的InvocationHandler类

 


3、调用构造方法创建动态类的实例对象,并将编写的InvocationHandler类的实例对象传进去

 


4、打印创建的对象和调用对象的没有返回值的方法和getClass方法,演示调用其他有返回值的方法报告了

 

 

异常。

 


5、将创建动态类的实例对象的代理改成匿名内部类的形式编写,锻炼大家习惯匿名内部类。

 

 

动态代理的原理图:

 

 

 

 

编写代理类:

 

 

         通过反射得到构造方法,创建代理对象:

 

Constructor constructor = clazzProxy1.getConstructor(InvocationHandler.class);
		Collection proxy1 = (Collection) constructor.newInstance(new InvocationHandler(){

			@Override
			public Object invoke(Object proxy, Method method, Object[] args)
					throws Throwable {
				
				return null;
			}
			
		});

 

 

由代理直接创建代理对象:

 

Collection proxy2 = (Collection)Proxy.newProxyInstance(
				Collection.class.getClassLoader(),
				new Class[]{Collection.class},
				new InvocationHandler(){

					ArrayList target = new ArrayList();
					@Override
					public Object invoke(Object proxy, Method method,
							Object[] args) throws Throwable {
						Object retVal = method.invoke(target, args);
						
						return retVal;
					}
					
				}
				);

 

 

AOP简单框架的实现:

 

 

 工厂类BeanFactory负责创建目标类或代理类的实例对象,并通过配置文件实现切换。其getBean方法根据

 

 

参数字符串返回一个相应的实例对象,如果参数字符串在配置文件中对应的类名不是ProxyFactoryBean

 

 

则直接返回该类的实例对象,否则,返回该类实例对象的getProxy方法返回的对象。

 

 

ProxyFacotryBean充当封装生成动态代理的工厂,需要为工厂类提供目标(target)、通告(advice)。

 

 

ProxyFactoryBean代码:

 

public class ProxyFactoryBean {

	private Advice advice;//要插入的系统功能代码
	
	private Object target;//目标对象
	
	public Advice getAdvice() {
		return advice;
	}

	public void setAdvice(Advice advice) {
		this.advice = advice;
	}

	public Object getTarget() {
		return target;
	}

	public void setTarget(Object target) {
		this.target = target;
	}

	//获得代理对象
	public Object getProxy() {
		Object proxy = Proxy.newProxyInstance(//由代理类直接创建代理对象
				target.getClass().getClassLoader(),//目标对象的类加载器
				target.getClass().getInterfaces(),//目标对象实现的接口
				new InvocationHandler(){
				
					public Object invoke(Object proxy, Method method, Object[] args)
							throws Throwable {

						advice.beforeMethod(method);//方法前advice
						Object retVal = method.invoke(target, args);//调用目标要调用的方法
						advice.afterMethod(method);//方法后advice
						return retVal;						
						
					}
				}
				);
		return proxy;
	}
}

 

 

BeanFactory代码:

 

 

public class BeanFactory {

	Properties props = new Properties();
	//使用构造方法导入资源配置文件
	public BeanFactory(InputStream ips) {
		
		try {
			props.load(ips);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	//获得bean方法
	public Object getBean(String name) {
		String className = props.getProperty(name);
		
		Class clazz = null;
		Object bean = null;
		try {
			clazz = Class.forName(className);//加载这个类
			bean = clazz.newInstance();//创建该类的对象
			
		} catch (ClassNotFoundException e) {
			
			e.printStackTrace();
			
		} catch (InstantiationException e) {
			e.printStackTrace();
			
		} catch (IllegalAccessException e) {
			e.printStackTrace();
			
		}
		
		if(bean instanceof ProxyFactoryBean) {//判断这个类是不是代理
			Object proxy = null;
			try {
				ProxyFactoryBean proxyFactoryBean = (ProxyFactoryBean) bean;//拿到一个代理bean工厂
				//创建advice
				Advice advice = (Advice) Class.forName(
						props.getProperty(name + ".advice")).newInstance();
				//创建目标对象
				Object target = Class.forName(
						props.getProperty(name + ".target")).newInstance();
				proxyFactoryBean.setAdvice(advice);
				proxyFactoryBean.setTarget(target);
				proxy = proxyFactoryBean.getProxy();
			} catch (Exception e) {
				e.printStackTrace();
			}
			return proxy;
		}
		return bean;
	}
}

 

 

MyAdvice代码:

 

public class MyAdvice implements Advice {
	
	private long beginTime = 0;

	@Override
	public void afterMethod(Method method) {
		
		long endTime = System.currentTimeMillis();
		System.out.println(method.getName() + " running time of " + (endTime - beginTime));
	}

	@Override
	public void beforeMethod(Method method) {

		beginTime = System.currentTimeMillis();
	}

}

  

 

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

  • 大小: 38 KB
  • 大小: 32.3 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics