无侵入式的给方法增强功能
1,真正干活的对象
2,代理对象
3,利用代理调用方法
切记一点:代理可以增强或者拦截的方法都在接口中,接口需要写在newProxyInstance的第二个参数里。
- public class Test {
- public static void main(String[] args) {
- /*
- 需求:
- 外面的人想要大明星唱一首歌
- 1. 获取代理的对象
- 代理对象 = ProxyUtil.createProxy(大明星的对象);
- 2. 再调用代理的唱歌方法
- 代理对象.唱歌的方法("只因你太美");
- */
- //1. 获取代理的对象
- BigStar bigStar = new BigStar("鸡哥");
- Star proxy = ProxyUtil.createProxy(bigStar);
-
- //2. 调用唱歌的方法
- String result = proxy.sing("只因你太美");
- System.out.println(result);
- }
- }
- /*
- *
- * 类的作用:
- * 创建一个代理
- *
- * */
- public class ProxyUtil {
- /*
- *
- * 方法的作用:
- * 给一个明星的对象,创建一个代理
- *
- * 形参:
- * 被代理的明星对象
- *
- * 返回值:
- * 给明星创建的代理
- *
- *
- *
- * 需求:
- * 外面的人想要大明星唱一首歌
- * 1. 获取代理的对象
- * 代理对象 = ProxyUtil.createProxy(大明星的对象);
- * 2. 再调用代理的唱歌方法
- * 代理对象.唱歌的方法("只因你太美");
- * */
- public static Star createProxy(BigStar bigStar){
- /* java.lang.reflect.Proxy类:提供了为对象产生代理对象的方法:
-
- public static Object newProxyInstance(ClassLoader loader, Class>[] interfaces, InvocationHandler h)
- 参数一:用于指定用哪个类加载器,去加载生成的代理类
- 参数二:指定接口,这些接口用于指定生成的代理长什么,也就是有哪些方法
- 参数三:用来指定生成的代理对象要干什么事情*/
- Star star = (Star) Proxy.newProxyInstance(
- ProxyUtil.class.getClassLoader(),//参数一:用于指定用哪个类加载器,去加载生成的代理类
- new Class[]{Star.class},//参数二:指定接口,这些接口用于指定生成的代理长什么,也就是有哪些方法
- //参数三:用来指定生成的代理对象要干什么事情
- new InvocationHandler() {
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- /*
- * 参数一:代理的对象
- * 参数二:要运行的方法 sing
- * 参数三:调用sing方法时,传递的实参
- * */
- if("sing".equals(method.getName())){
- System.out.println("准备话筒,收钱");
- }else if("dance".equals(method.getName())){
- System.out.println("准备场地,收钱");
- }
- //去找大明星开始唱歌或者跳舞
- //代码的表现形式:调用大明星里面唱歌或者跳舞的方法
- return method.invoke(bigStar,args);
- }
- }
- );
- return star;
- }
- }
- public interface Star {
- //我们可以把所有想要被代理的方法定义在接口当中
- //唱歌
- public abstract String sing(String name);
- //跳舞
- public abstract void dance();
- }
- public class BigStar implements Star {
- private String name;
-
-
- public BigStar() {
- }
-
- public BigStar(String name) {
- this.name = name;
- }
-
- //唱歌
- @Override
- public String sing(String name){
- System.out.println(this.name + "正在唱" + name);
- return "谢谢";
- }
-
- //跳舞
- @Override
- public void dance(){
- System.out.println(this.name + "正在跳舞");
- }
-
- /**
- * 获取
- * @return name
- */
- public String getName() {
- return name;
- }
-
- /**
- * 设置
- * @param name
- */
- public void setName(String name) {
- this.name = name;
- }
-
- public String toString() {
- return "BigStar{name = " + name + "}";
- }
- }
-
动态代理,还可以拦截方法
比如:
在这个故事中,经济人作为代理,如果别人让邀请大明星去唱歌,打篮球,经纪人就增强功能。
但是如果别人让大明星去扫厕所,经纪人就要拦截,不会去调用大明星的方法。
- /*
- * 类的作用:
- * 创建一个代理
- * */
- public class ProxyUtil {
- public static Star createProxy(BigStar bigStar){
- public static Object newProxyInstance(ClassLoader loader, Class>[] interfaces, InvocationHandler h)
- Star star = (Star) Proxy.newProxyInstance(
- ProxyUtil.class.getClassLoader(),
- new Class[]{Star.class},
- new InvocationHandler() {
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- if("cleanWC".equals(method.getName())){
- System.out.println("拦截,不调用大明星的方法");
- return null;
- }
- //如果是其他方法,正常执行
- return method.invoke(bigStar,args);
- }
- }
- );
- return star;
- }
- }
对add方法进行增强,对remove方法进行拦截,对其他方法不拦截也不增强
- public class MyProxyDemo1 {
- public static void main(String[] args) {
- //动态代码可以增强也可以拦截
- //1.创建真正干活的人
- ArrayList
list = new ArrayList<>(); -
- //2.创建代理对象
- //参数一:类加载器。当前类名.class.getClassLoader()
- // 找到是谁,把当前的类,加载到内存中了,我再麻烦他帮我干一件事情,把后面的代理类,也加载到内存
-
- //参数二:是一个数组,在数组里面写接口的字节码文件对象。
- // 如果写了List,那么表示代理,可以代理List接口里面所有的方法,对这些方法可以增强或者拦截
- // 但是,一定要写ArrayList真实实现的接口
- // 假设在第二个参数中,写了MyInter接口,那么是错误的。
- // 因为ArrayList并没有实现这个接口,那么就无法对这个接口里面的方法,进行增强或拦截
- //参数三:用来创建代理对象的匿名内部类
- List proxyList = (List) Proxy.newProxyInstance(
- //参数一:类加载器
- MyProxyDemo1.class.getClassLoader(),
- //参数二:是一个数组,表示代理对象能代理的方法范围
- new Class[]{List.class},
- //参数三:本质就是代理对象
- new InvocationHandler() {
- @Override
- //invoke方法参数的意义
- //参数一:表示代理对象,一般不用(了解)
- //参数二:就是方法名,我们可以对方法名进行判断,是增强还是拦截
- //参数三:就是下面第三步调用方法时,传递的参数。
- //举例1:
- //list.add("阿玮好帅");
- //此时参数二就是add这个方法名
- //此时参数三 args[0] 就是 阿玮好帅
- //举例2:
- //list.set(1, "aaa");
- //此时参数二就是set这个方法名
- //此时参数三 args[0] 就是 1 args[1]"aaa"
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- //对add方法做一个增强,统计耗时时间
- if (method.getName().equals("add")) {
- long start = System.currentTimeMillis();
- //调用集合的方法,真正的添加数据
- method.invoke(list, args);
- long end = System.currentTimeMillis();
- System.out.println("耗时时间:" + (end - start));
- //需要进行返回,返回值要跟真正增强或者拦截的方法保持一致
- return true;
- }else if(method.getName().equals("remove") && args[0] instanceof Integer){
- System.out.println("拦截了按照索引删除的方法");
- return null;
- }else if(method.getName().equals("remove")){
- System.out.println("拦截了按照对象删除的方法");
- return false;
- }else{
- //如果当前调用的是其他方法,我们既不增强,也不拦截
- method.invoke(list,args);
- return null;
- }
- }
- }
- );
-
- //3.调用方法
- //如果调用者是list,就好比绕过了第二步的代码,直接添加元素
- //如果调用者是代理对象,此时代理才能帮我们增强或者拦截
-
- //每次调用方法的时候,都不会直接操作集合
- //而是先调用代理里面的invoke,在invoke方法中进行判断,可以增强或者拦截
- proxyList.add("aaa");
- proxyList.add("bbb");
- proxyList.add("ccc");
- proxyList.add("ddd");
-
- proxyList.remove(0);
- proxyList.remove("aaa");
-
-
- //打印集合
- System.out.println(list);
- }
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-