Java----代理

什么是代理?

         在Java中,代理是一种用于创建一个或多个服务的中间层,它可以拦截并处理程序对实际服务对象的请求。代理模式是一种设计模式,属于结构型模式,它允许程序员在不修改实际对象代码的情况下,增强或控制对它的访问。

Java中的代理可以分为以下几种类型:

1.静态代理

静态代理在编译时就已经确定代理类和原始类的关系。代理类通常与原始类实现相同的接口,然后在代理类中维护一个原始对象的引用,从而可以在调用原始对象方法前后添加额外的处理逻辑(例如日志记录、权限校验等)。


interface IService {
    void doSomething();
}


class Service implements IService {
    public void doSomething() {
        System.out.println("执行业务逻辑");
    }
}


class ServiceProxy implements IService {
    private IService service;

    public ServiceProxy(IService service) {
        this.service = service;
    }

    public void doSomething() {
        System.out.println("前置处理");
        service.doSomething();
        System.out.println("后置处理");
    }
}

2.动态代理

动态代理是在运行时动态创建的代理方式,不需要在编译时确定代理类。Java提供了java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口来支持动态代理。动态代理可以代理任何实现了接口的类。

我们需要准备我们对象:

package com.wxy.proxy;

//将需要代理操作的方法声明在接口中,并继承该接口
public class BigStar implements Star{

    public BigStar() {
    }

    public BigStar(String name) {
        this.name = name;
    }

    @Override
    public String sing(String name) {
        System.out.println(name + "正在唱歌");
        return "表演唱歌完毕";
    }

    @Override
    public String dance(String name) {
        System.out.println(name + "正在跳舞");
        return "表演跳舞完毕";
    }

    private String 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 + "}";
    }
}

将我们需要拓展功能的方法声明在接口中,并让原来的类继承它:

package com.wxy.proxy;

//声明对应的代理方法
public interface Star {
    String sing(String name);
    String dance(String name);
}

然后我们就可以开始编写代理类了,需要注意是该内部类的involk方法是在测试类中使用代理(接口star对象)调用其方法时,会自动调用其involk方法,该involk有三个参数,在源码是这样描述的:

proxy -方法上调用方法的代理实例-对应于代理实例上调用的接口方法的方法实例。

Method对象的声明类将是在其中声明方法的接口,该接口可能是代理类继承该方法所通过的代理接口的超接口。

Args -一个对象数组,其中包含在代理实例的方法调用中传递的参数值,如果接口方法不接受参数,则为空。基本类型的参数被包装在适当的基本包装类的实例中,例如java.lang.Integer或java.lang.Boolean。

package com.wxy.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

//代理工具类
public class ProxyUtil {

    //使用静态修饰方便调用,可直接使用类名进行调用
    public static Star createProxy(BigStar bigStar){
        //对我们需要进行代理的方法构建代理对象
        Star star = (Star) Proxy.newProxyInstance(
                //参数一:用于指定使用哪个类去加载生成加载的代理类,指定加载器,这里我们直接使用当前类的加载器
                ProxyUtil.class.getClassLoader(),
                //参数二:需要代理的字节码对象数组,指定接口这些接口指定生成的代张什么样,也就是说有哪些方法需要代理
                new Class[]{Star.class},
                //参数三:用来指定生成的代理对象要干什么事情,可用Lambda表达式进行简化
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        if(method.getName().equals("sing")){
                            System.out.println("现在是唱歌业务");

                        }else if(method.getName().equals("dance")){
                            System.out.println("现在是跳舞业务");
                        }
                        System.out.println("做好前置工作");
                        //这里才是我们正在要改造的方法,我们在这里通过反射的方法运行我们原先的代码
                        String result = (String) method.invoke(bigStar, args);
                        System.out.println("做好后置工作");
                        //将原先的返回值进行返回
                        return result;
                    }
                }
        );

        return star;
    }
}

编写测试类查看结果:

package com.wxy.proxy;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class TestForProxy {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //通过反射的方法来创建我们的对象
        Class<?> classz = Class.forName("com.wxy.proxy.BigStar");
        //指定使用我要使用参数是String类型的构造方法
        Constructor<?> constructor = classz.getDeclaredConstructor(String.class);
        //通过该构造方法我们来创建我们的对象
        BigStar xiaoming = (BigStar) constructor.newInstance("小明");
        //将我们的对象传递给我们的代理,然后拿到代理对象,使用代理对象来调用我们的方法,而不是使用以前的对象调用原先的方法!!!
        Star proxy = ProxyUtil.createProxy(xiaoming);
        System.out.println(proxy.sing(xiaoming.getName()));
        System.out.println(proxy.dance(xiaoming.getName()));
    }
}

输出结果如下:

 

3.CGLIB代理

CGLIB(Code Generation Library)是一个强大的高性能代码生成库,它被用来在运行时生成类的子类,通过方法拦截的方式实现对原始类的增强。CGLIB代理不需要原始类实现任何接口,因此它适用于无法修改源代码的情况。

拓展:

        代理模式在Java中的应用非常广泛,如Spring框架中的AOP(面向切面编程)就是通过代理模式来实现的。代理可以用于多种场景,包括但不限于日志记录、性能监控、事务管理、安全控制等。

总结:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值