# SpringBoot 中设计模式的使用

Posted MarlonBrando1998

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了# SpringBoot 中设计模式的使用相关的知识,希望对你有一定的参考价值。

SpringBoot 中设计模式的使用

友情链接:设计模式的使用:https://blog.csdn.net/qq_37248504/article/details/122991309

简单工厂

  • 简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类。
  • SpringBoot中的BeanFactory就是简单工厂模式的体现,根据传入一个唯一的标识来获得Bean对象,但是否是在传入参数后创建还是传入参数前创建这个要根据具体情况来定。

BeanFactory 类图

工厂方法

  • 使用示例:FactoryBean接口。

  • SpringBoot 中体现就是Mybatis mapper中方法的实现,mapper接口并没有具体的实现类,但是在注入的时候并不会报错,Mybatis结合代理模式,在 getObject()中返回一个代理的Bean

示例代码

  • 实现 FactoryBean接口,重写getObject(),这个方法返回的是一个具体的Bean,而不是 FactoryBean
  • 结合代理模式,在getObject()中返回一个代理对象的Bean
public class EngineFactory implements FactoryBean<CarEngine>, BeanNameAware, InvocationHandler 

    private static final Logger logger = LoggerFactory.getLogger(EngineFactory.class);

    private String name;

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable 
        if ("fire".equalsIgnoreCase(method.getName())) 
            logger.info(LogConst.LOG_SUCCESS_PREFIX + "here is invoke  engine:" + method.getName());
        
        if ("close".equalsIgnoreCase(method.getName())) 
            logger.info(LogConst.LOG_SUCCESS_PREFIX + "here is invoke  engine:" + method.getName());
        
        return null;
    

    @Override
    public void setBeanName(String name) 
        this.name = name;
    

    /**
     * 获取引擎 CarEngine 的代理对象
     *
     * @return
     */
    @Override
    public CarEngine getObject() 
        logger.info(LogConst.LOG_SUCCESS_PREFIX + "EngineFactory  to build Engine01 , EngineFactory :" + name);
        CarEngine carEngine = (CarEngine) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]CarEngine.class, this);
        return carEngine;
    

    @Override
    public Class<?> getObjectType() 
        return CarEngine.class;
    

    /**
     * 是否是单例 Bean
     *
     * @return
     */
    @Override
    public boolean isSingleton() 
        return true;
    

单例模式

  • FactoryBean中获取Bean的时候使用单例模式
@Autowired
private ApplicationContext applicationContext;

Object testService = applicationContext.getBean("testServiceImpl");

单例模式获取 Bean源码分析

  • FactoryBeangetBean方法再获取容器中Bean的时候使用了单例模式
//一级缓存:用于存放完全初始化好的 bean,从该缓存中取出的 bean 可以直接使用
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
// 二级缓存:提前曝光的单例对象的cache,存放原始的 bean 对象(尚未填充属性),用于解决循环依赖
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16); 
// 三级缓存:单例对象工厂的cache,存放 bean 工厂对象,用于解决循环依赖
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); 

@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) 
    // 检查缓存中是否存在实例
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) 
        // 提前曝光的单例对象的缓存中获取Bean
        singletonObject = this.earlySingletonObjects.get(beanName);
        if (singletonObject == null && allowEarlyReference) 
            //如果为空,则锁定全局变量并进行处理。
            synchronized (this.singletonObjects) 
                // 在完整的单例锁中一致地创建早期引用
                singletonObject = this.singletonObjects.get(beanName);
                if (singletonObject == null) 
                    singletonObject = this.earlySingletonObjects.get(beanName);
                    if (singletonObject == null) 
            			//当某些方法需要提前初始化的时候则会调用addSingleFactory 方法将对应的ObjectFactory初始化策略存储在singletonFactories
                        ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                        if (singletonFactory != null) 
                            // 调用预先设定的getObject方法
                            singletonObject = singletonFactory.getObject();
                            // 放在缓存中
                            this.earlySingletonObjects.put(beanName, singletonObject);
                            this.singletonFactories.remove(beanName);
                        
                    
                
            
        
    
    return singletonObject;

流程图

适配器模式

  • 适配器模式的别名为包装器(Wrapper)模式,它既可以作为类结构型模式,也可以作为对象结构型模式。在适配器模式定义中所提及的接口是指广义的接口,它可以表示一个方法或者方法的集合。

Aop 中的应用

  • Spring AOPAdvisorAdapter 类有 4 个实现类,即 SimpleBeforeAdviceAdapterMethodBeforeAdviceAdapterAfterReturningAdviceAdapterThrowsAdviceAdapter
  • Spring 会根据不同的 AOP 配置来确定使用对应的 Advice,与策略模式不同的是,一个方法可以同时拥有多个 Advice

模板方法

  • 定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。它是一种类行为型模式。

容器启动过程 refresh() 中方法

@Override
public void refresh() throws BeansException, IllegalStateException 
    synchronized (this.startupShutdownMonitor) 
        // 准备刷新的上下文,系统属性以及环境变量等
        prepareRefresh();
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        prepareBeanFactory(beanFactory);
        try 
            postProcessBeanFactory(beanFactory);
            invokeBeanFactoryPostProcessors(beanFactory);
            registerBeanPostProcessors(beanFactory);
            initMessageSource();
            initApplicationEventMulticaster();
            onRefresh();
            registerListeners();
            finishBeanFactoryInitialization(beanFactory);
            finishRefresh();
        
    

protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) 

  • postProcessBeanFactory() 在多个类中有重写。抽象模式的体现

Jdbctemplate

  • 使用jdbcTemplate只需写sql,然后对执行结果进行处理,省去了建立数据库连接与连接释放资源的重复操作,其中用的是模板方法设计模式,把重复的动作封装起来,需要处理的部分开放接口,让调用者去实现。
public abstract class MyJdbcTemplate 

    private static final Logger logger = LoggerFactory.getLogger(MyJdbcTemplate.class);

    /**
     * 数据源
     */
    private DataSource dataSource;

    /**
     * 构造方法初始化 dataSource
     *
     * @param dataSource 数据源
     */
    public MyJdbcTemplate(DataSource dataSource) 
        this.dataSource = dataSource;
    

    /**
     * Jdbc Sql 查询过程
     *
     * @param sql    sql
     * @param values values
     * @return List
     */
    public final List<?> executeQuery(String sql, Object[] values) 
        try 
            Connection connection = this.getConnection();
            PreparedStatement pre = this.createPrepareStatement(connection, sql);
            ResultSet resultSet = this.executeQuery(pre, values);
            List<Object> result = new ArrayList<>();
            while (resultSet.next()) 
                result.add(rowMapper(resultSet));
            
            resultSet.close();
            pre.close();
            connection.close();
            return result;
         catch (Exception exception) 
            logger.error("Error occurred :", exception);
        
        return null;
    

    /**
     * 由子类实现
     *
     * @param resultSet
     * @return
     * @throws SQLException
     */
    protected abstract Object rowMapper(ResultSet resultSet) throws SQLException;

    /**
     * 执行查询
     *
     * @param preparedStatement preparedStatement
     * @param values            values
     * @return ResultSet
     * @throws SQLException
     */
    private ResultSet executeQuery(PreparedStatement preparedStatement, Object[] values) throws SQLException 
        for (int i = 0; i < values.length; i++) 
            preparedStatement.setObject(i, values[i]);
        
        return preparedStatement.executeQuery();
    

    /**
     * 对 SQL 语句进行预编译的操作
     *
     * @param connection connection
     * @param sql        sql
     * @return PreparedStatement
     * @throws SQLException
     */
    private PreparedStatement createPrepareStatement(Connection connection, String sql) throws SQLException 
        return connection.prepareStatement(sql);
    

    /**
     * 获取连接
     *
     * @return Connection
     * @throws SQLException
     */
    private Connection getConnection() throws SQLException 
        return this.dataSource.getConnection();
    

观察者模式

  • 观察者模式是一种对象行为型模式。它表示的是一种对象与对象之间具有依赖关系,当一个对象发生改变的时候,这个对象所依赖的对象也会做出反应。
  • Spring 事件驱动模型就是观察者模式很经典的一个应用。Spring 事件驱动模型非常有用,在很多场景都可以解耦我们的代码。

事件角色

  • spring-context下默认的事件
  • ContextStartedEventApplicationContext 启动后触发的事件;
  • ContextStoppedEventApplicationContext 停止后触发的事件;
  • ContextRefreshedEventApplicationContext 初始化或刷新完成后触发的事件;
  • ContextClosedEventApplicationContext 关闭后触发的事件。

事件监听者角色

  • ApplicationListener 充当了事件监听者角色,它是一个接口,里面只定义了一个 onApplicationEvent()方法来处理ApplicationEventApplicationListener接口类源码如下,可以看出接口定义看出接口中的事件只要实现了 ApplicationEvent就可以了。所以,在 Spring中我们只要实现 ApplicationListener 接口实现 onApplicationEvent() 方法即可完成监听事件
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener 

	/**
	 * Handle an application event.
	 * @param event the event to respond to
	 */
	void onApplicationEvent(E event);


事件发布者角色

  • ApplicationEventPublisher 充当了事件的发布者,它也是一个接口。
public interface ApplicationEventPublisher 

	default void publishEvent(ApplicationEvent event) 
		publishEvent((Object) event);
	

	void publishEvent(Object event);

SpringBoot 使用事件示例见:https://blog.csdn.net/qq_37248504/article/details/115269995

代理模式

Spring Aop 的动态代理

  • getObject()ProxyFactoryBeangetObject 初始化通知链,然后根据通知生成实例对象
public Object getObject() throws BeansException 
    initializeAdvisorChain();
    if (isSingleton()) 
        return getSingletonInstance();
    
    else 
        if (this.targetName == null) 
            logger.info("Using non-singleton proxies with singleton targets is often undesirable. " +
                        "Enable prototype proxies by setting the 'targetName' property.");
        
        return newPrototypeInstance();
    

  • getSingletonInstance:获取代理,然后获取实例
//创建Aop动态代理,然后获取实例
this.singletonInstance = getProxy(createAopProxy());

Mybatis Mapper 代理的实现

详细见: https://blog.csdn.net/qq_37248504/article/details/108371768

策略模式

  • Resource接口是具体资源访问策略的抽象,也是所有资源访问类所实现的接口。
public interface Resource extends InputStreamSource 

	// 返回 Resource 所指向的资源是否存在
	boolean exists();

    default boolean isReadable() 
		return exists();
	

	// 返回 Resource 所指向的资源是否存在
	default boolean isOpen() 
		return false;
	


	default boolean isFile() 
		return false;
	

	// 返回 Resource 所指向的资源是否存在
	URL getURL() throws IOException;

	URI getURI() throws IOException;

	// 返回 Resource 所指向的资源是否存在
	File getFile() throws IOException;

	default ReadableByteChannel readableChannel() throws IOException 
		return Channels.newChannel(getInputStream());
	

	long contentLength() throws IOException;

	long lastModified() throws IOException;

	Resource createRelative(String relativePath) throws IOException;

	@Nullable
	String getFilename();

	// 返回资源的描述信息,通常用于资源处理出错时输出该信息,通常是全限定文件名或实际 URL
	String getDescription();

  • Resource 接口本身没有提供访问任何底层资源的实现逻辑,针对不同的底层资源,Spring 将会提供不同的 Resource 实现类,不同的实现类负责不同的资源访问逻辑。

Spring Resource 接口

SpringResource 接口提供了如下实现类:

  • UrlResource:访问网络资源的实现类。
  • ClassPathResource:访问类加载路径里资源的实现类
  • FileSystemResource:访问文件系统里资源的实现类。
  • ServletContextResource:访问相对于 ServletContext 路径里的资源的实现类
  • InputStreamResource:访问输入流资源的实现类。
  • ByteArrayResource:访问字节数组资源的实现类。

提供访问任何底层资源的实现逻辑,针对不同的底层资源,Spring 将会提供不同的 Resource 实现类,不同的实现类负责不同的资源访问逻辑。

以上是关于# SpringBoot 中设计模式的使用的主要内容,如果未能解决你的问题,请参考以下文章

电商门户网站商品品类多级联动SpringBoot+Thymeleaf实现

Java学习笔记——对比简单工厂模式和策略模式

创造型设计模式-----工厂方法模式

设计模式--简单工厂模式

23种设计模式——简单工厂设计模式

简单工厂模式