一、类加载器
1.类加载器的作用
2.类加载器的分类
类加载器有三种,不同类加载器加载不同的
1)BootStrap:引导类加载器:加载都是最基础的文件
2)ExtClassLoader:扩展类加载器:加载都是基础的文件
3)AppClassLoader:应用类加载器:三方jar包和自己编写java文件
3.获得类加载器
字节码对象.getClassLoader();
public class Demo { public static void main(String[] args) { Class clazz=Demo.class; //获得Demo的字节码对象 ClassLoader classLoader = clazz.getClassLoader();//获得类加载器 //getResource的参数路径相对classes(src) classLoader.getResource("database.properties");//获得classes(src)下的任何资源 }
二、动态代理
1.什么是动态代理(中介)
调用对象(需要租房的人)----->代理对象(中介)------>目标对象(房主)
2.动态代理 :
不用手动编写一个代理对象,不需要一一编写与目标对象相同的方法,这个过程,在运行时的内存中动态生成代理对象。------字节码对象级别的代理对象
分类:
基于子类的动态代理
基于接口的动态代理
1)基于接口的动态代理的:
* 动态代理的API:Proxy中存在一个生成动态代理的的方法newProxyInstance
返回值:Object就是代理对象;
参数:loader:代表与目标对象相同的类加载器-------目标对象.getClass().getClassLoader();
interfaces:代表与目标对象实现的所有的接口字节码对象数组;
h:具体的代理的操作,InvocationHandler接口
步骤:
1.代理对象和真实对象实现相同的接口;
2.代理对象=proxy.newProxyInstance();
3.使用代理对象调用方法
4.增强方法; 方式:1.增强参数列表;2.增强返回值类型;3.增强方法体执行逻辑
案例:
用户------------------->> 代理商(代理对象) --------------->联想公司(真实对象)
//目标对象的接口 public interface SaleComputer { public String sale(double money); }
/** * 目标类 */ public class Lenovo implements SaleComputer{ @Override public String sale(double money) { System.out.println("花了"+money+"元买了一台电脑"); return "联想电脑"; } }
/** * 代理类 * * @author 撑起一片阳光 * */ public class MyAnnoTest { public static void main(String[] args) { Lenovo lenovo = new Lenovo (); /** * 三个参数: 1.类加载器:真实对象.getClass.getClassLoader * 2.接口数组: 真实对象.getClass.getInterface * 3.处理器:new InvocationHandler() * 此方法返回一个代理对象,然后转成和目标对象相同的接口 */ SaleComputer proxy = (SaleComputer) Proxy.newProxyInstance(lenovo.getClass().getClassLoader(), lenovo.getClass().getInterfaces(), new InvocationHandler() { /** * 代理逻辑编写的方法:代理对象调用的所有方法都会触发改方法执行 参数: 1.proxy:代理对象(不用) * 2.method:代理对象调用的方法,被封装为对象 * 3.args:代理对象调用方法时传入的参数 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // System.out.println("该方法执行了"); // System.out.println(method.getName());//返回sale // System.out.println(args[0]);//8000 if (method.getName().equals("sale")) { // 获取到该方法的参数 // 1.增强参数 double money = (double) args[0]; //3.增强方法体 System.out.println("专车接你去买电脑"); money = money * 0.85; // 参数值修改后代理对象回扣1200返回6800给真实对象 System.out.println("免费送货"); // 使用真实对象调用该方法 Object obj = method.invoke(lenovo , money); //增强返回值 return obj+"+鼠标"; } else { Object obj = method.invoke(lenovo , args); return obj; } } }); // 3.调用方法 String sale = proxy.sale(8000);//用户花了8000 System.out.println(sale); } }
2)基于子类的动态代理
涉及的类:Enhancer
提供者:第三方的cglib库
* 创建代理对象:使用Enhancer类中的create方法
注意:代理的类不能为最终类
实现步骤:
第一步:导入依赖
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>2.1_3</version> </dependency>
第二步:实现:
** * 生产者,要代理的类 */ public class Produce { /** * 销售 * @param money */ public void saleProduce(float money){ System.out.println("销售产品,并拿到钱"+money); } /** * 售后 * @param money */ public void afterService(float money){ System.out.println("提供售后服务,并拿到钱"+money); } }
** * 模拟消费者 */ public class Client { public static void main(String[] args) { final Produce produce = new Produce(); /** * 动态代理 * creat方法参数: * Class:字节码 * 它是用于指定被代理对象的字节码 * Callback:用于提供增强的代码 * 它是用于我们写如何代理,一般都写一个该接口的实现类,通常情况下都是匿名但不必须 * 此接口的实现类谁用谁写 * 一般写该接口的子接口实现类类,MethodInterceptor */ Produce cglibProduce= (Produce) Enhancer.create(produce.getClass(), new MethodInterceptor() { /** * 执行被代理对象的任何方法都会经过该方法 * * @param proxy * @param method * @param args 以上的三个参数和基于接口的中invoke方法的参数一样 * @param methodProxy:当前执行方法的代理对象 * @return * @throws Throwable */ @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { //增强的代码 Object returnValue = null; //1.获取方法执行参数 Float money = (Float) args[0]; //2.判断当前方法是不是销售 if ("saleProduce".equals(method.getName())) { returnValue = method.invoke(produce, money * 0.8f); } return returnValue; } }); cglibProduce.saleProduce(15555f); } }