当前位置: 代码网 > it编程>编程语言>Java > Java面试题:Spring框架除了IOC和AOP,还有哪些好玩的设计模式?

Java面试题:Spring框架除了IOC和AOP,还有哪些好玩的设计模式?

2024年05月16日 Java 我要评论
Spring是一个基于Java的企业级应用程序开发框架,它使用了多种设计模式来实现其各种特性和功能。本文将介绍一些在Spring中使用的常见设计模式以及相应的代码示例和说明。 ...

spring是一个基于java的企业级应用程序开发框架,它使用了多种设计模式来实现其各种特性和功能。本文将介绍一些在spring中使用的常见设计模式以及相应的代码示例和说明。

单例模式

单例模式是spring中最常用的设计模式之一。在applicationcontext中,bean默认为单例模式。当我们创建一个bean时,默认情况下它就是单例的。这意味着当bean被请求时,spring会返回相同的实例。下面是一个示例代码:

public class mybean {
    // ...
}

@configuration
public class appconfig {

    @bean
    public mybean mybean() {
        return new mybean();
    }

}

在上面的代码中,mybean()方法返回了mybean类的实例,这个实例将作为单例对象存在于applicationcontext中。

 

在spring aop中,切面默认为单例模式。这意味着切面对象只会创建一次,并与所有目标对象共享。下面的代码演示了如何在spring aop中配置一个单例切面:

@aspect
@component
public class loggingaspect {

    @before("execution(* com.example.service.*.*(..))")
    public void logbefore(joinpoint joinpoint) {
        // ...
    }

}

这里,loggingaspect类用@aspect注解进行了标注,它包含了@before通知,该通知将在com.example.service包中的所有方法执行前执行。由于loggingaspect是一个@component,所以它将被spring自动扫描并创建一个单例实例。

在spring mvc中,控制器(controller)也通常是单例的。下面是一个简单的控制器类示例:

@controller
public class usercontroller {
    @autowired
    private userservice userservice;

    @getmapping("/users/{id}")
    public responseentity<user> getuserbyid(@pathvariable long id) {
        user user = userservice.getuserbyid(id);
        return responseentity.ok(user);
    }

}

 

工厂模式

在spring框架中工厂模式是一种常用的模式之一。下面我将介绍spring中使用工厂模式的几个具体示例:

beanfactory

spring 的核心容器是beanfactory和其子接口applicationcontext。其中,beanfactory使用了工厂模式来创建和管理bean实例。它包含了创建、配置和管理 bean 的所有功能,如下所示:

public interface beanfactory {
    object getbean(string name) throws beansexception;

    <t> t getbean(string name, class<t> requiredtype) throws beansexception;

    boolean containsbean(string name);
}

上述代码中,beanfactory接口定义了一个getbean()方法,通过传入bean的名称或类型,返回相应的bean实例。这里的getbean()方法就是工厂方法。

 

factorybean

factorybean 是 spring 中另一个使用工厂模式的类。它用于创建复杂的 bean,这些 bean 可以有自己的生命周期、作用域和依赖项等。

public interface factorybean<t> {

    t getobject() throws exception;

    class<?> getobjecttype();

    boolean issingleton();
}

述代码中,factorybean 定义了一个getobject()方法,用于创建并返回一个特定类型的bean。该方法会在应用程序需要访问bean时被调用。

 

messagesource

spring 的国际化支持是基于messagesource接口实现的。messagesource为应用程序提供了访问消息资源的方法,如下所示:

public interface messagesource {
    string getmessage(string code, object[] args, string defaultmessage, locale locale);
}

上述代码中,getmessage()方法使用工厂模式创建和管理消息资源。它接收消息代码、参数、默认消息和语言环境等参数,并返回相应的消息字符串。

 

代理模式

在spring aop中,代理模式被广泛应用。spring使用jdk动态代理和cglib代理来创建切面。下面是一个简单的使用注解方式配置切面的示例:

@aspect
@component
public class loggingaspect {

    @before("execution(public * com.example.service.*.*(..))")
    public void logbefore(joinpoint joinpoint) {
        // ...
    }

}

在上面的代码中,loggingaspect类使用了@aspect和@component注解进行标注,表明它是一个切面,并会被spring自动扫描并创建代理对象。在@before通知中,执行方法调用前进行日志记录。

 

在spring事务管理中,代理模式也被广泛使用。spring使用动态代理技术来实现声明式事务管理。下面是一个使用@transactional注解来声明事务的示例:

@service
public class userserviceimpl implements userservice {
    @autowired
    private userrepository userrepository;

    @override
    @transactional
    public user createuser(user user) {
        return userrepository.save(user);
    }

}

在上面的代码中,createuser()方法使用@transactional注解标记,spring将在该方法调用之前创建一个代理对象。当然,这只是一个简单的示例,实际上,在复杂的应用程序中,spring可以再通过多种方式来声明式事务。

 

对于spring mvc中的控制器类,我们也可以使用代理模式来增强其功能,例如在控制器方法之前和之后添加日志记录。下面是一个基于注解方式实现aop拦截器的示例:

@aspect
@component
public class logginginterceptor {

    @before("execution(* com.example.controller.*.*(..))")
    public void logbefore(joinpoint joinpoint) {
        // ...
    }

    @afterreturning(value = "execution(* com.example.controller.*.*(..))", returning = "result")
    public void logafterreturning(joinpoint joinpoint, object result) {
        // ...
    }

}

在上面的代码中,logginginterceptor类使用了@aspect和@component注解进行标注,表明它是一个切面,并且会被spring自动扫描并创建代理对象。在@before通知中,执行方法调用前进行日志记录,在@afterreturning通知中,执行方法调用后进行日志记录。

 

观察者模式

spring中的事件机制也是基于观察者模式实现的。在spring中,所有的bean都可以作为事件源发布事件,其他的bean则可以通过注册监听器来响应这些事件。

applicationeventpublisher

applicationeventpublisher是spring 框架中使用观察者模式的一个类。它负责发布事件并通知已注册的监听器。以下是applicationeventpublisher的代码示例:

public interface applicationeventpublisher {
    void publishevent(applicationevent event);
}

上述代码中,publishevent()方法用于发布一个事件,并通知已注册的所有监听器。具体的监听器实现可以通过实现applicationlistener接口来完成。

 

applicationcontext 

applicationcontext是spring的核心接口之一。它扩展了beanfactory接口,并在其基础上添加了更多的功能,例如事件发布和提供环境信息等。以下是 applicationcontext使用观察者模式的代码示例:

public interface applicationcontext extends environmentcapable, listablebeanfactory, hierarchicalbeanfactory,
        messagesource, applicationeventpublisher, resourcepatternresolver {

    void publishevent(applicationevent event);

    string[] getbeannamesfortype(resolvabletype type);

    <t> map<string, t> getbeansoftype(class<t> type) throws beansexception;
}

上述代码中,publishevent()方法也用于发布事件,并通知已注册的所有监听器。与 applicationeventpublisher不同的是,applicationcontext继承了多个接口,这使得它可以处理各种类型的事件。

 

beanpostprocessor 

beanpostprocessor是spring框架中一个可插入的回调接口,用于在bean实例化和配置的过程中提供扩展点。以下是beanpostprocessor使用观察者模式的代码示例:

public interface beanpostprocessor {
    object postprocessbeforeinitialization(object bean, string beanname) throws beansexception;
    object postprocessafterinitialization(object bean, string beanname) throws beansexception;
}

postprocessbeforeinitialization()和postprocessafterinitialization()方法分别在bean实例化和初始化之前/之后被调用。可以将这些方法视为钩子函数,可以在其中添加自定义逻辑以修改或扩展bean的默认行为。

 

责任链模式 

责任链模式是一种行为型设计模式,它允许你将请求沿着处理链传递,直到其中一个处理程序处理该请求。

handlerinterceptor 

handlerinterceptor是spring mvc中使用责任链模式的一个类。它提供了多个方法,例如 prehandle()、posthandle()和aftercompletion()等,可以在请求处理过程中拦截并修改请求和响应。以下是handlerinterceptor的代码示例:

public interface handlerinterceptor {

    boolean prehandle(httpservletrequest request, httpservletresponse response, object handler) throws exception;

    void posthandle(httpservletrequest request, httpservletresponse response, object handler,
                    @nullable modelandview modelandview) throws exception;

    void aftercompletion(httpservletrequest request, httpservletresponse response, object handler,
                         @nullable exception ex) throws exception;
}

上述代码中,handlerinterceptor提供了三个方法,分别在请求处理前、处理后、以及完成后调用。通过实现这些方法,在请求处理过程中可以执行自定义逻辑,例如验证用户身份、记录日志等。

 

abstractrequestloggingfilter

abstractrequestloggingfilter是spring中使用责任链模式的另一个类。它提供了预先和后续处理请求和响应的方法,可以进行访问日志记录。

以下是 abstractrequestloggingfilter的代码示例:

public abstract class abstractrequestloggingfilter extends onceperrequestfilter {

    protected void beforerequest(httpservletrequest request, string message) {}

    protected void afterrequest(httpservletrequest request, string message) {}
}

上述代码中,abstractrequestloggingfilter的beforerequest()和afterrequest()方法分别在请求处理前和处理后调用。通过实现这些方法,可以记录访问日志,包括请求的地址、参数等信息。

 

handlerexceptionresolver

handlerexceptionresolver是spring mvc中使用责任链模式的另一个类。它提供了多个方法,例如resolveexception()和shouldhandle()等,可以处理异常并决定是否继续执行下一个处理器。以下是handlerexceptionresolver的代码示例:

public interface handlerexceptionresolver {

    @nullable
    modelandview resolveexception(httpservletrequest request, httpservletresponse response, @nullable object handler,
            exception ex);

    boolean shouldhandle(httpservletrequest request, @nullable exception ex);
}

上述代码中,handlerexceptionresolver的resolveexception()方法用于处理异常并返回modelandview对象,该对象可以包含自定义的错误页面或其他错误信息。而 shouldhandle()方法则用于判断是否应该由当前处理器处理异常,如果返回false,则会继续执行下一个处理器。

 

模板方法模式 

模板方法模式是一种行为型设计模式,它定义了一个算法的骨架,并允许子类实现算法中的某些步骤。在spring框架中,jdbctemplate和hibernatetemplate就是使用了模板方法模式的例子。

jdbctemplate 

jdbctemplate是spring中使用模板方法模式的一个类。它提供了多个方法,例如 update()、query()等,可以执行sql语句并返回结果。以下是jdbctemplate的代码示例:

public class jdbctemplate {

    public <t> t execute(connectioncallback<t> action) throws dataaccessexception {
        // ...
    }

    // ...

    public int update(string sql, object... args) throws dataaccessexception {
        // ...
    }

    public <t> list<t> query(string sql, object[] args, rowmapper<t> rowmapper) throws dataaccessexception {
        // ...
    }

    // ...
}

上述代码中,jdbctemplate 提供了execute()、update()和query()等方法,它们都使用了模板方法模式。其中,execute()方法是一个模板方法,它接受一个 connectioncallback对象并执行其中的doinconnection()方法,该方法由子类实现。而 update()和 query()方法也是模板方法,它们都调用了execute()方法,并传入不同的参数。

 

hibernatetemplate 

hibernatetemplate是spring中使用模板方法模式的另一个类。它提供了多个方法,例如 save()、delete()等,可以操作hibernate实体并返回结果。以下是hibernatetemplate 的代码示例:

public class hibernatetemplate extends hibernateaccessor {

    public object execute(hibernatecallback<?> action) throws dataaccessexception {
        // ...
    }

    // ...

    public void save(object entity) throws dataaccessexception {
        // ...
    }

    public void delete(object entity) throws dataaccessexception {
        // ...
    }

    // ...
}

上述代码中,hibernatetemplate提供了 execute()、save()和 delete()等方法,它们也都使用了模板方法模式。其中,execute()方法是一个模板方法,它接受一个 hibernatecallback对象并执行其中的doinhibernate()方法,该方法由子类实现。而 save()和delete()方法也是模板方法,它们都调用了execute()方法,并传入不同的参数。

 

策略模式

在spring框架中,策略模式被广泛应用于各种场景,例如事务管理、缓存管理等。以下是 spring中使用策略模式的几个具体示例:

事务管理 

spring提供了多种事务管理方式,其中之一就是基于策略模式实现的。该模式下,开发人员需要将不同的事务属性(如传播行为、隔离级别等)封装到transactiondefinition 接口的实现类中,并将其作为参数传递给platformtransactionmanager的方法。以下是一个示例代码:

public class transactionaltest {

    private platformtransactionmanager transactionmanager;

    public void settransactionmanager(platformtransactionmanager transactionmanager) {
        this.transactionmanager = transactionmanager;
    }

    public void dotransactional() {
        defaulttransactiondefinition definition = new defaulttransactiondefinition();
        definition.setpropagationbehavior(transactiondefinition.propagation_required);
        definition.setisolationlevel(transactiondefinition.isolation_read_committed);

        transactionstatus status = transactionmanager.gettransaction(definition);

        try {
            // 执行事务操作
            transactionmanager.commit(status);
        } catch (exception e) {
            transactionmanager.rollback(status);
        }
    }
}

上述代码中,transactionaltest类使用了策略模式来管理事务。它将 defaulttransactiondefinition对象作为参数传递给platformtransactionmanager的方法,并在try-catch块中执行事务操作。

 

缓存管理 

spring 提供了多种缓存管理方式,其中之一就是基于策略模式实现的。该模式下,开发人员需要将不同的缓存属性(如缓存类型、缓存超时时间等)封装到cachemanager和cache 接口的实现类中,并将其作为参数传递给cacheresolver和cache的方法。以下是一个示例代码:

public class cachetest {

    private cacheresolver cacheresolver;

    public void setcacheresolver(cacheresolver cacheresolver) {
        this.cacheresolver = cacheresolver;
    }

    public void docached() {
        cache cache = cacheresolver.resolvecache("mycache");

        object value = cache.get("mykey");
        if (value == null) {
            // 从数据库或其他存储介质中获取数据
            value = "myvalue";

            cache.put("mykey", value);
        }
    }
}

上述代码中,cachetest类使用了策略模式来管理缓存。它将cacheresolver对象作为参数传递给resolvecache()方法,并根据缓存的键值对判断是否需要从缓存中获取数据。

 

往期面试题:

java面试题:如果你这样做,你会后悔的,两次启动同一个线程~~~

java面试题:@postconstruct、init-method和afterpropertiesset执行顺序?

java面试题:simpledateformat是线程安全的吗?使用时应该注意什么?

java面试题:细数threadlocal大坑,内存泄露本可避免

java面试题:请谈谈对threadlocal的理解?

java面试题:为什么hashmap不建议使用对象作为key?

java面试题:你知道spring的ioc吗?那么,它为什么这么重要呢?

java面试题:线程池内“闹情绪”的线程,怎么办?

java面试题:spring bean线程安全?别担心,只要你不写并发代码就好了!

 

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com