栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

设计模式十三:结构型-代理模式

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

设计模式十三:结构型-代理模式

结构型模式:代理模式

文章目录
    • 结构型模式:代理模式
      • 代理模式
        • 1、代理模式:介绍
        • 2、代理模式:模拟场景
        • 3、代理模式:代码实现
        • 4、代理模式:总结

代理模式 1、代理模式:介绍
  • 代理模式
    • 为了方便访问某些资源,使对象类更加易用,从而在操作上使用的代理服务
  • 代理模式经常会出现在系统或组件中,它们提供一种非常简单易用的方式,控制原本需要编写很多代码才能实现的服务类
    • 在数据库访问层面会提供一个比较基础的应用,避免在对应用服务扩容时造成数据库连接数暴增
    • 使用过的一些中间件,例如 RPC 框架,在拿到 jar 包对接口的描述后,中间件会在服务启动时生成对应的代理类。
      • 当调用接口时,实际使通过代理类发出的 Socket 信息
    • 常用的 MyBatis 基本功能是定义接口,不需要写实现类就可以对 XML 或自定义注解里的 SQL 语句增删改查
2、代理模式:模拟场景

  • MyBatis-Spring 中代理类场景
    • 当使用 MyBatis 时,只需要定义接口,而不需要写实现类就可以完成增删改查操作。
    • 通过代理类交给 Spring 管理的过程介绍代理类模式。
3、代理模式:代码实现
  • 介绍如何用代理模式实现在 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 MapperFactoryBean implements 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、代理模式:总结
  • 代理模式除了 用于开发中间件,还可用于对服务进行包装、物联网组件等。
    • 让复杂的各项服务变为轻量级调用和缓存使用。
  • 代理模式的设计方式可以让代码更加整洁、干净,易于维护
    • 虽然在这部分开发过程中额外增加了很多类,但是这种中间件的复用性极高,也更加智能,也可以非常方便地扩展到各种服务应用中
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/328265.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号