- 结构型模式:代理模式
- 代理模式
- 1、代理模式:介绍
- 2、代理模式:模拟场景
- 3、代理模式:代码实现
- 4、代理模式:总结
- 代理模式
- 为了方便访问某些资源,使对象类更加易用,从而在操作上使用的代理服务。
- 代理模式经常会出现在系统或组件中,它们提供一种非常简单易用的方式,控制原本需要编写很多代码才能实现的服务类
- 在数据库访问层面会提供一个比较基础的应用,避免在对应用服务扩容时造成数据库连接数暴增
- 使用过的一些中间件,例如 RPC 框架,在拿到 jar 包对接口的描述后,中间件会在服务启动时生成对应的代理类。
- 当调用接口时,实际使通过代理类发出的 Socket 信息
- 常用的 MyBatis 基本功能是定义接口,不需要写实现类就可以对 XML 或自定义注解里的 SQL 语句增删改查
- MyBatis-Spring 中代理类场景
- 当使用 MyBatis 时,只需要定义接口,而不需要写实现类就可以完成增删改查操作。
- 通过代理类交给 Spring 管理的过程介绍代理类模式。
- 介绍如何用代理模式实现在 MyBatis 中对类的代理,也就是只需定义接口,就可以关联到方法注解中的 SQL 语句,完成对数据库的操作
- BeanDefinitionRegistryPostProcessor:Spring 的接口类用于处理对 Bean 的定义注册
- GenericBeanDefinition:用于定义Bean 的信息,与在 MyBatis-Spring 中使用的 ScannedGenericBeanDefinition 略有不同
- FactoryBean:用于处理Bean 工厂的类。
0、工程结构
lino-design-14.0
|——src
|——main
|--java
|--com.lino
|--agent
|--MapperFactoryBean.java
|--RegisterBeanFactory.java
|--Select.java
|--IUserDao.java
|--resources
|--spring-config.xml
|--test
|--java
|--com.lino.test
|--Test.java
- 左侧对应的是功能的使用,右侧对应的是中间件的实现部分
- 以上类主要做的事情是:将类的代理注册到 Spring 中,把对象 Bean 交给 Spring 管理,也就起到了 代理 的作用
1、自定义注解
import java.lang.annotation.*;
@documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Select {
String value() default "";
}
2、Dao层接口
import com.lino.agent.Select;
public interface IUserDao {
@Select("select userName from user where id = #{uId}")
String queryUserInfo(String uId);
}
3、代理类定义
- MapperFactoryBean:实现对代理类的定义
- 通过继承 FacoryBean,提供 Bean,也就是方法 T getObject()
- 在方法 getObject() 中提供类的代理,并模拟对 SQL 语句的处理,这里包含了当用户调用 Dao 层方法时的处理逻辑。
- 还有最上面提供构造函数透传需要被代理的类 Class
mapperInterface - getObjectType() 提供对象类型反馈,且 isSingleton() 返回类是单例的
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.FactoryBean; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class MapperFactoryBeanimplements FactoryBean { private Logger logger = LoggerFactory.getLogger(MapperFactoryBean.class); 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); logger.info("SQL:{}", select.value().replace("#{uId}", args[0].toString())); return args[0] + " 沉淀、分享、成长,让自己和他人都能有所收获!"; }; return (T) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{mapperInterface}, handler); } @Override public Class> getObjectType() { return mapperInterface; } @Override public boolean isSingleton() { return true; } }
4、将Bean定义注册到Spring容器
- 将代理的 Bean 交给 Spring 容器管理,可以非常方便地获取代理的对象 Bean。这部分是 Spring 中关于一个对象 Bean 的注册过程。
- GenericBeanDefinition 用于定义一个对象 Bean 的基本信息 setBeanClass(MapperFactoryBean.class)
- 也可以把 IUserDao 接口类通过 addGenericArgumentValue(IUserDao.class) 透传给构造函数
- 最后使用 BeanDefinitionReaderUtils.registerBeanDefinition 注册对象 Bean,也就是注册到 DefaultListableBeanFactory 中
import com.lino.IUserDao;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.GenericBeanDefinition;
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 {
// left intentionally blank
}
}
5、配置文件spring-config
6、单元测试
- 测试过程:通过加载 Bean 工厂,获取代理类的实例对象,之后调用方法并返回结构。
- 可以看到,接口 IUserDao 没有一个硬编码的实现类,而是通过使用代理的方式给接口生成一个实现类,并交给 Spring 管理
import com.lino.IUserDao;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
private Logger logger = LoggerFactory.getLogger(Test.class);
@org.junit.Test
public void testIUserDao() {
BeanFactory beanFactory = new ClassPathXmlApplicationContext("spring-config.xml");
IUserDao userDao = beanFactory.getBean("userDao", IUserDao.class);
String res = userDao.queryUserInfo("100001");
logger.info("测试结果:{}", res);
}
}
- 测试结果
10:53:18.937 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'userDao' 10:53:18.937 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'userDao' 10:53:18.952 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Eagerly caching bean 'userDao' to allow for resolving potential circular references 10:53:18.977 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'userDao' 10:53:18.979 [main] INFO o.s.b.f.s.DefaultListableBeanFactory - Overriding bean definition for bean 'userDao' with a different definition: replacing [Generic bean: class [com.lino.agent.RegisterBeanFactory]; scope=; abstract=false; lazyInit=false; autowireMode=1; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [spring-config.xml]] with [Generic bean: class [com.lino.agent.MapperFactoryBean]; scope=singleton; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null] 10:53:18.981 [main] DEBUG o.s.c.s.ClassPathXmlApplicationContext - Unable to locate MessageSource with name 'messageSource': using default [org.springframework.context.support.DelegatingMessageSource@2bea5ab4] 10:53:18.983 [main] DEBUG o.s.c.s.ClassPathXmlApplicationContext - Unable to locate ApplicationEventMulticaster with name 'applicationEventMulticaster': using default [org.springframework.context.event.SimpleApplicationEventMulticaster@70a9f84e] 10:53:18.984 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1563da5: defining beans [userDao]; root of factory hierarchy 10:53:18.984 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'userDao' 10:53:18.984 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'userDao' 10:53:19.001 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Eagerly caching bean 'userDao' to allow for resolving potential circular references 10:53:19.001 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'userDao' 10:53:19.002 [main] DEBUG o.s.c.s.ClassPathXmlApplicationContext - Unable to locate LifecycleProcessor with name 'lifecycleProcessor': using default [org.springframework.context.support.DefaultLifecycleProcessor@49e202ad] 10:53:19.002 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'lifecycleProcessor' 10:53:19.004 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Could not find key 'spring.liveBeansView.mbeanDomain' in any property source 10:53:19.005 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'userDao' 10:53:19.042 [main] INFO com.lino.agent.MapperFactoryBean - SQL:select userName from user where id = 100001 10:53:19.042 [main] INFO com.lino.test.Test - 测试结果:100001 沉淀、分享、成长,让自己和他人都能有所收获!4、代理模式:总结
- 代理模式除了 用于开发中间件,还可用于对服务进行包装、物联网组件等。
- 让复杂的各项服务变为轻量级调用和缓存使用。
- 代理模式的设计方式可以让代码更加整洁、干净,易于维护
- 虽然在这部分开发过程中额外增加了很多类,但是这种中间件的复用性极高,也更加智能,也可以非常方便地扩展到各种服务应用中



