spring设计模式详解,java常见的设计模式
- 数据库
- 2023-08-13
- 88
很多朋友对于spring设计模式详解和java常见的设计模式不太懂,今天就由小编来为大家分享,希望可以帮助到大家,下面一起来看看吧!spring框架包含工厂方法模式吗当...
很多朋友对于spring设计模式详解和java常见的设计模式不太懂,今天就由小编来为大家分享,希望可以帮助到大家,下面一起来看看吧!
spring框架包含工厂方法模式吗
当然了。.xml文件就是相当于那个工厂了。其实就是动态代理的实现嘛
Spring是如何运用设计模式的
关于设计模式,如果使用得当,将会使我们的代码更加简洁,并且更具扩展性。本文主要讲解Spring中如何使用策略模式,工厂方法模式以及Builder模式。
1.策略模式(Java自学网【javazx.com】)
关于策略模式的使用方式,在Spring中其实比较简单,从本质上讲,策略模式就是一个接口下有多个实现类,而每种实现类会处理某一种情况。我们以发奖励为例进行讲解,比如我们在抽奖系统中,有多种奖励方式可供选择,比如积分,虚拟币和现金等。在存储时,我们必然会使用一个类似于type的字段用于表征这几种发放奖励的,那么这里我们就可以使用多态的方式进行奖励的发放。比如我们抽象出一个PrizeSender的接口,其声明如下:
publicinterfacePrizeSender{
/**
*用于判断当前实例是否支持当前奖励的发放
*/
booleansupport(SendPrizeRequestrequest);
/**
*发放奖励
*/
voidsendPrize(SendPrizeRequestrequest);
}
该接口中主要有两个方法:support()和sendPrize(),其中support()方法主要用于判断各个子类是否支持当前类型数据的处理,而sendPrize()则主要是用于进行具体的业务处理的,比如这里奖励的发放。下面就是我们三种不同类型的奖励发放的具体代码:
//积分发放
@Component
publicclassPointSenderimplementsPrizeSender{
@Override
publicbooleansupport(SendPrizeRequestrequest){
returnrequest.getPrizeType()==PrizeTypeEnum.POINT;
}
@Override
publicvoidsendPrize(SendPrizeRequestrequest){
System.out.println("发放积分");
}
}
//虚拟币发放
@Component
publicclassVirtualCurrencySenderimplementsPrizeSender{
@Override
publicbooleansupport(SendPrizeRequestrequest){
returnPrizeTypeEnum.VIRTUAL_CURRENCY==request.getPrizeType();
}
@Override
publicvoidsendPrize(SendPrizeRequestrequest){
System.out.println("发放虚拟币");
}
}
//现金发放
@Component
publicclassCashSenderimplementsPrizeSender{
@Override
publicbooleansupport(SendPrizeRequestrequest){
returnPrizeTypeEnum.CASH==request.getPrizeType();
}
@Override
publicvoidsendPrize(SendPrizeRequestrequest){
System.out.println("发放现金");
}
}
这里可以看到,在每种子类型中,我们只需要在support()方法中通过request的某个参数来控制当前request是否是当前实例能够处理的类型,如果是,则外层的控制逻辑就会将request交给当前实例进行处理。关于这个类的设计,有几个点需要注意:
使用@Component注解对当前类进行标注,将其声明为Spring容器所管理的一个bean;
声明一个返回boolean值的类似于support()的方法,通过这个方法来控制当前实例是否为处理目标request的实例;
声明一个类似于sendPrize()的方法用于处理业务逻辑,当然根据各个业务的不同声明的方法名肯定是不同的,这里只是一个对统一的业务处理的抽象;
无论是support()方法还是sendPrize()方法,都需要传一个对象进行,而不是简简单单的基本类型的变量,这样做的好处是后续如果要在Request中新增字段,那么就不需要修改接口的定义和已经实现的各个子类的逻辑;
2.工厂方法模式
上面我们讲解了如何使用Spring来声明一个策略模式,那么如何为不同的业务逻辑来注入不同的bean呢,或者说外层的控制逻辑是什么样的,这里我们就可以使用工厂方法模式了。所谓的工厂方法模式,就是定义一个工厂方法,通过传入的参数,返回某个实例,然后通过该实例来处理后续的业务逻辑。一般的,工厂方法的返回值类型是一个接口类型,而选择具体子类实例的逻辑则封装到了工厂方法中了。通过这种方式,来将外层调用逻辑与具体的子类的获取逻辑进行分离。如下图展示了工厂方法模式的一个示意图:
可以看到,工厂方法将具体实例的选择进行了封装,而客户端,也就是我们的调用方只需要调用工厂的具体方法获取到具体的事例即可,而不需要管具体的实例实现是什么。上面我们讲解了Spring中是如何使用策略模式声明处理逻辑的,而没有讲如何选择具体的策略,这里我们就可以使用工厂方法模式。如下是我们声明的一个PrizeSenderFactory:
@Component
publicclassPrizeSenderFactory{
@Autowired
privateList<PrizeSender>prizeSenders;
publicPrizeSendergetPrizeSender(SendPrizeRequestrequest){
for(PrizeSenderprizeSender:prizeSenders){
if(prizeSender.support(request)){
returnprizeSender;
}
}
thrownewUnsupportedOperationException("unsupportedrequest:"+request);
}
}
这里我们声明一个了一个工厂方法getPrizeSender(),其入参就是SendPrizeRequest,而返回值是某个实现了PrizeSender接口的实例,可以看到,通过这种方式,我们将具体的选择方式下移到了具体的子类中的,因为当前实现了PrizeSender的bean是否支持当前request的处理,是由具体的子类实现的。在该工厂方法中,我们也没有任何与具体子类相关的逻辑,也就是说,该类实际上是可以动态检测新加入的子类实例的。这主要是通过Spring的自动注入来实现的,主要是因为我们这里注入的是一个List<PrizeSender>,也就是说,如果有新的PrizeSender的子类实例,只要其是Spring所管理的,那么都会被注入到这里来。下面就是我们编写的一段用于测试的代码来模拟调用方的调用:
@Service
publicclassApplicationService{
@Autowired
privatePrizeSenderFactoryprizeSenderFactory;
publicvoidmockedClient(){
SendPrizeRequestrequest=newSendPrizeRequest();
request.setPrizeType(PrizeTypeEnum.POINT);//这里的request一般是根据数据库或外部调用来生成的
PrizeSenderprizeSender=prizeSenderFactory.getPrizeSender(request);
prizeSender.sendPrize(request);
}
}
在客户端代码中,首先通过PrizeSenderFactory获取一个PrizeSender实例,然后通过其sendPrize()方法发放具体的奖励,通过这种方式,将具体的奖励发放逻辑与客户端调用进行了解耦。而且根据前面的讲解,我们也知道,如果新增了一种奖励方式,我们只需要声明一个新的实现了PrizeSender的bean即可,而不需要对现有代码进行任何修改。
3.Builder模式
关于Builder模式,我想使用过lombok的同学肯定会说builder模式非常的简单,只需要在某个bean上使用@Builder注解进行声明即可,lombok可以自动帮我们将其声明为一个Builder的bean。关于这种使用方式,本人不置可否,不过就我的理解,这里主要有两个点我们需要理解:
Builder模式就其名称而言,是一个构建者,我更倾向于将其理解为通过一定的参数,通过一定的业务逻辑来最终生成某个对象。如果仅仅只是使用lombok的这种方式,其本质上也还是创建了一个简单的bean,这个与通过getter和setter方式构建一个bean是没有什么大的区别的;
在Spring框架中,使用设计模式最大的问题在于如果在各个模式bean中能够注入Spring的bean,如果能够注入,那么将大大的扩展其使用方式。因为我们就可以真的实现通过传入的简单的几个参数,然后结合Spring注入的bean进行一定的处理后,以构造出我们所需要的某个bean。显然,这是lombok所无法实现的;
关于Builder模式,我们可以以前面奖励发放的SendPrizeRequest的构造为例进行讲解。在构造request对象的时候,必然是通过前台传如的某些参数来经过一定的处理,最后生成一个request对象。那么我们就可以使用Builder模式来构建一个SendPrizeRequest。这里假设根据前台调用,我们能够获取到prizeId和userId,那么我们就可以创建一个如下的SendPrizeRequest:
publicclassSendPrizeRequest{
privatefinalPrizeTypeEnumprizeType;
privatefinalintamount;
privatefinalStringuserId;
publicSendPrizeRequest(PrizeTypeEnumprizeType,intamount,StringuserId){
this.prizeType=prizeType;
this.amount=amount;
this.userId=userId;
}
@Component
@Scope("prototype")
publicstaticclassBuilder{
@Autowired
PrizeServiceprizeService;
privateintprizeId;
privateStringuserId;
publicBuilderprizeId(intprizeId){
this.prizeId=prizeId;
returnthis;
}
publicBuilderuserId(StringuserId){
this.userId=userId;
returnthis;
}
publicSendPrizeRequestbuild(){
Prizeprize=prizeService.findById(prizeId);
returnnewSendPrizeRequest(prize.getPrizeType(),prize.getAmount(),userId);
}
}
publicPrizeTypeEnumgetPrizeType(){
returnprizeType;
}
publicintgetAmount(){
returnamount;
}
publicStringgetUserId(){
returnuserId;
}
}
这里就是使用Spring维护一个Builder模式的示例,具体的维护方式就是在Builder类上使用@Component和@Scope注解来标注该Builder类,这样我们就可以在Builder类中注入我们所需要的实例来进行一定的业务处理了。关于该模式,这里有几点需要说明:
在Builder类上必须使用@Scope注解来标注该实例为prototype类型,因为很明显,我们这里的Builder实例是有状态的,无法被多线程共享;
在Builder.build()方法中,我们可以通过传入的参数和注入的bean来进行一定的业务处理,从而得到构建一个SendPrizeRequest所需要的参数;
Builder类必须使用static修饰,因为在Java中,如果内部类不用static修饰,那么该类的实例必须依赖于外部类的一个实例,而我们这里本质上是希望通过内部类实例来构建外部类实例,也就是说内部类实例存在的时候,外部类实例是还不存在的,因而这里必须使用static修饰;
根据标准的Builder模式的使用方式,外部类的各个参数都必须使用final修饰,然后只需要为其声明getter方法即可。
上面我们展示了如何使用Spring的方式来声明一个Builder模式的类,那么我们该如何进行使用呢,如下是我们的一个使用示例:
@Service
publicclassApplicationService{
@Autowired
privatePrizeSenderFactoryprizeSenderFactory;
@Autowired
privateApplicationContextcontext;
publicvoidmockedClient(){
SendPrizeRequestrequest=newPrizeSendRequestBuilder()
.prizeId(1)
.userId("u4352234")
.build();
PrizeSenderprizeSender=prizeSenderFactory.getPrizeSender(request);
prizeSender.sendPrize(request);
}
publicBuildernewPrizeSendRequestBuilder(){
returncontext.getBean(Builder.class);
}
}
上述代码中,我们主要要看一下newPrizeSendRequestBuilder()方法,在Spring中,如果一个类是多例类型,也即使用@Scope("prototype")进行了标注,那么每次获取该bean的时候就必须使用ApplicationContext.getBean()方法获取一个新的实例,至于具体的原因,读者可查阅相关文档。我们这里就是通过一个单独的方法来创建一个Builder对象,然后通过流式来为其设置prizeId和userId等参数,最后通过build()方法构建得到了一个SendPrizeRequest实例,通过该实例来进行后续的奖励发放。
4.小结
本文主要通过一个奖励发放的示例来对Spring中如何使用工厂方法模式,策略模式和Builder模式的方式进行讲解,并且着重强调了实现各个模式时我们所需要注意的点。
spring中有几种事务处理方式各自优缺点是什么
1,Spring有两种事务管理方式:①编程式②声明式。编程式的比较灵活,但是代码量大,存在重复的代码比较多;而声明式事务管理比编程式更灵活方便。 基于AOP的声明式事务管理,实质就是在方法执行前后进行拦截,然后在方法执行前创建并加入事务,执行完目标方法后根据执行情况提交事务或者回滚事务。 声明式事务管理有两种形式:①配置文件②在业务方法上加上@Transaction注解,将事务规则应用到业务逻辑中。 2,Spring的事务管理接口主要有三个:TransactionDefinition、PlatformTransactionManager、TransactionStatus。
springboot最常用的两种微服务方式说那两种
springboot常用的微服务方式为jar包和war包启动。
spring 事务管理 两种方式
Spring事务管理方式有两种
1)编程式事务:以java编码的方式来实现事务的管理。基本不使用。
2)声明式事务:只需要申明配置事务的处理方式,spring会自动进行事务管理。
a.事务管理器
b.事务的传播特性:事务的传播特性用来定义事务中又存在事务的情况下,该如何来处理事务。(Service层方法调用service层方法时)
a)Required:必须,必须有一个事务,如果没有,则会开启一个事务。如果有,则使用当前事务。(默认)
b)Requireds_new:(需要自己的新的事务)必须运行在自己的事务中,即使当前方法存在一个事务,也会新建一个自己的事务。执行本身事务时,会将外部事务挂起。
c)Nested:(嵌套)可以多个事务嵌套在一起,内部事务不会影响外部事务,外部事务回滚,会影响到内部事务回滚。
d)Mandtory:(必须有事务)要求必须有事务,没有事务就抛出异常。
e)Never:(永不)不支持事务,有事务就抛出异常。
f)Supports:(支持)如果有事务和没有事务都支持。
g)not_supported:(不支持事务),有事务存在,便不运行,直到事务提交后再执行。
spring入门详解
Spring是一个轻量级的Java框架,它提供了许多功能强大的工具和库,用于简化Java开发过程中的许多常见任务。如果您想深入了解Spring,以下是一些入门详解:
1.Spring框架的核心概念:Spring框架由多个模块组成,每个模块都提供了不同的功能。其中最核心的概念是IoC(InversionofControl)和DI(DependencyInjection),它们可以帮助我们管理应用程序中的对象和依赖关系。
2.Spring的核心容器:Spring框架的核心容器是BeanFactory和ApplicationContext,它们可以管理应用程序中的对象和依赖关系。BeanFactory是一个较早的版本,而ApplicationContext是一个较新的版本,它提供了更多的功能和扩展。
3.SpringMVC:SpringMVC是Spring框架中的一个模块,它提供了一个基于模型-视图-控制器(MVC)模式的Web应用程序开发框架。它可以帮助我们轻松地创建Web应用程序,并提供了许多有用的功能,如数据绑定、表单验证和国际化等。
4.SpringBoot:SpringBoot是一个快速开发框架,它可以帮助我们快速创建基于Spring框架的Web应用程序。它可以自动配置许多常见的Spring特性,如数据源、消息队列和安全性等。
5.SpringSecurity:SpringSecurity是一个用于身份验证和授权的框架,它可以帮助我们保护Web应用程序免受未经授权的访问。它提供了许多有用的功能,如身份验证、授权、密码重置等。
关于spring设计模式详解的内容到此结束,希望对大家有所帮助。
本文链接:http://xinin56.com/su/6104.html