【玩转23种Java设计模式】结构型模式篇,关于分布式系统架构的优点

一、简介


代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

它的组成:

  • 抽象角色:通过接口或抽象类声明真实角色实现的业务方法。

  • 代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。

  • 真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。

二、实例


这次举例可能难度大了一点,因为这个是代理模式是“大厂面试热点”,所以打算通过Mybatis举例说一下。如果看懂这个,以后被问到“代理模式在什么框架中有应用?”、“Mybatis中使用了什么

《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》

【docs.qq.com/doc/DSmxTbFJ1cmN1R2dB】 完整内容开源分享

设计模式?怎么用的”…等等,咱们至少能答上来一部分。

模拟实现⼀个Mybatis中对类的代理过程,只需要定义接⼝,就可以关联到⽅法注解中的 sql 语句完成对数据库的操作。简单模拟下,实际源码肯定更复杂点。

1、自定义注解(Select)

定义了⼀个模拟mybatis-spring中的自定义注解,使用在方法层面。

@Documented

@Retention(RetentionPolicy.RUNTIME)

@Target({ElementType.METHOD})

public @interface Select {

String value() default “”;

}

2、Dao层接口(IUserDao)

public interface IUserDao {

@Select(“select * from user where id = #{id}”)

String selectById(Integer id);

}

3、代理类(MapperFactoryBean)

@Slf4j

public class MapperFactoryBean implements FactoryBean {

private Class mapperInterface;

public MapperFactoryBean(Class mapperInterface) {

this.mapperInterface = mapperInterface;

}

@Override

public T getObject() throws Exception {

InvocationHandler handler = (proxy, method, args) -> {

Select select = method.getAnnotation(Select.class);

log.info(“query sql:{}”, select.value());

log.info(“param:{}”, args[0]);

return “1, 张三(模拟从数据库查询的返回)”;

};

return (T) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{mapperInterface}, handler);

}

@Override

public Class<?> getObjectType() {

return mapperInterface;

}

@Override

public boolean isSingleton() {

return true;

}

}

MapperFactoryBean 通过继承 FactoryBean ,提供bean对象,也就是方法T getObject() 。在方法 getObject() 中提供类的代理以及模拟对sql语句的处理,这里包含了用户调用dao层方法时候的处理逻辑。

4、Bean定义注册到Spring容器(RegisterBeanFactory)

public class RegisterBeanFactory implements BeanDefinitionRegistryPostProcessor {

@Override

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {

GenericBeanDefinition beanDefinition = new GenericBeanDefinition();

beanDefinition.setBeanClass(MapperFactoryBean.class);

beanDefinition.setScope(“singleton”);

beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(IUserDao.class);

BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(beanDefinition, “userDao”);

BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);

}

@Override

public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

}

}

我们将代理的bean交给spring容器管理,以方便我们获取到代理的bean。这里是在spring中关于⼀个bean注册过程的源码。GenericBeanDefinition ,用于定义⼀个bean的基本信息,也包括可以透传给构造函数信息,最后使用BeanDefinitionReaderUtils.registerBeanDefinition,进行bean的注册,也就是注册到DefaultListableBeanFactory 中。

5、spring-mybatis.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns=“http://www.springframework.org/schema/beans”

xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”

xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans.xsd">

6、测试

@SpringBootTest

public class ApplicationTests {

@Test

public void test() {

BeanFactory beanFactory = new ClassPathXmlApplicationContext(“spring-mybatis.xml”);

IUserDao userDao = beanFactory.getBean(“userDao”, IUserDao.class);

String res = userDao.selectById(1);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值