代理模式

代理模式

使用一个代理对象将对象包装起来,然后用该代理对象来取代该对象,任何对原始对象的调用都要通过代理,代理对象决定是否以及何时调用原始对象的方法 .

来源于这篇博客

以下例子来源于大神狂神!!!

1、静态代理

思维导图

1. Rent接口,负责出租房子的人和中介共同需要干的事出租房子

//租房
public interface Rent {

    //租房子
    public void rent();

}

2. Proxy表示中介去继承租房的接口

  • 房东只需要把房子交给中介就行了,有中介代理,中介有些自己的事情要做....
@Component(value = "proxy")
public class Proxy implements Rent{
    @Autowired
    @Qualifier("host")
    private Host host;

    public Proxy() {
    }

    public Proxy(Host host) {
        this.host = host;
    }

    @Override
    public void rent() {
        lookHouse();
        host.rent();
        signContract();
        harvestFees();
    }

    public void lookHouse(){
        System.out.println("看"  + host.getHostName() +"的房子");
    }

    public void signContract(){
        System.out.println("签合同");
    }

    public void harvestFees(){
        System.out.println("收中介费");
    }

}

3. 房东Host,需要出租房屋,他就只干一件事,租房子

@Component(value = "host")
public class Host implements Rent{

    private String hostName;

    public String getHostName() {
        return hostName;
    }

    public void setHostName(String hostName) {
        this.hostName = hostName;
    }

    @Override
    public void rent() {
        System.out.println("房东要出租房");
    }
}

4. 需要租房的人,People,需要找中介租房,不直接联系房东,由中介全权代理

//需要租房的人
public class People {

    @Test
    public void makeHouse(){

        ApplicationContext context = new AnnotationConfigApplicationContext(SsyConfig.class);

        Host host = context.getBean("host", Host.class);
        host.setHostName("水三丫");
        Proxy proxy = context.getBean("proxy", Proxy.class);
        proxy.rent();

    }
}

//运行结果
看水三丫的房子
房东要出租房
签合同
收中介费

Process finished with exit code 0

静态代理的缺点:一个真实的角色会参数一个代理角色,代码量会翻倍,需要动态代理来解决

2、动态代理

利用Java的反射技术(Java Reflection),在运行时创建一个实现某些给定接口的新类(也称“动态代理类”)及其实例(对象),代理的是接口(Interfaces),不是类(Class),也不是抽象类。在运行时才知道具体的实现,spring aop就是此原理。

参考一笑而过者也博客

2.1 需要了解两个类

  • Proxy:代理
    @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
  1. loader: 用哪个类加载器去加载代理对象

  2. interfaces:动态代理类需要实现的接口

  3. h:动态代理方法在执行时,会调用h里面的invoke方法去执行

  • InvocationHandler接口:调用处理程序

2.2 测试

  • 需要代理的接口
public interface UserService {

    public void add();

    public void update();

    public void delete();

    public void query();
}
  • 实现该接口的类
public class UserServiceImpl implements UserService{
    @Override
    public void add() {
        System.out.println("增加了一个用户");
    }

    @Override
    public void update() {
        System.out.println("更新了一个用户");
    }

    @Override
    public void delete() {
        System.out.println("删除了一个用户");
    }

    @Override
    public void query() {
        System.out.println("查询了一个用户");
    }
}
  • 实现该InvocationHandler接口的通过反射获取代理类的类
@Component("proxyInvocationHandler")
public class ProxyInvocationHandler implements InvocationHandler {

    private Object target;

    public Object getTarget() {
        return target;
    }

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

    //生成代理类
    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
    }


    //处理代理事例并返回结果,当代理类调用方法时会走这个method,invoke()
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        System.out.println(method.getName());
        before();
        Object result = method.invoke(target, args);
        after();
        return result;
    }

    public void before(){
        System.out.println("操作之前打印日志");
    }


    public void after(){
        System.out.println("操作之后打印日志");
    }
}
  • 需要操作的客户
public class UserServlet {

    @Test
    public void test(){
        ApplicationContext context = new AnnotationConfigApplicationContext(SsyConfigService.class);

        UserServiceImpl userServiceImpl = context.getBean("userService", UserServiceImpl.class);
        ProxyInvocationHandler pih = context.getBean("proxyInvocationHandler", ProxyInvocationHandler.class);

        pih.setTarget(userServiceImpl);


        UserService proxy = (UserService) pih.getProxy();

        proxy.update();
    }

}
posted @ 2022-03-25 17:19  水三丫  阅读(34)  评论(0编辑  收藏  举报