springmvc 绑定参数都为空?配置文件讲解
一、Spring Cloud Feign使用详解
通过前面两章对Spring Cloud Ribbon和Spring Cloud Hystrix的介绍,我们已经掌握了开发微服务应用时,两个重要武器,学会了如何在微服务架构中实现客户端负载均衡的服务调用以及如何通过断路器来保护我们的微服务应用。这两者将被作为基础工具类框架广泛地应用在各个微服务的实现中,不仅包括我们自身的业务类微服务,也包括一些基础设施类微服务(比如**)。此外,在实践过程中,我们会发现对这两个框架的使用几乎是同时出现的。既然如此,那么是否有更高层次的封装来整合这两个基础工具以简化开发呢?本章我们即将介绍的Spring Cloud Ribbon与Spring Cloud Hystrix,除了提供这两者的强大功能之外,它还提供了一种声明式的Web服务客户端定义方式。
我们在使用Spring Cloud Ribbon时,通常都会利用它对RestTemplate的请求拦截来实现对依赖服务的接口调用,而RestTemplate已经实现了对HTTP请求的封装处理,形成了一套模版化的调用方法。在之前的例子中,我们只是简单介绍了RestTemplate调用对实现,但是在实际开发中,由于对服务依赖对调用可能不止于一处,往往一个接口会被多处调用,所以我们通常都会针对各个微服务自行封装一些客户端累来包装这些依赖服务的调用。这个时候我们会发现,由于RestTemplate的封装,几乎每一个调用都是简单的模版化内容。综合上述这些情况,Spring Cloud Fegin在此基础上做了进一步封装,由它来帮助我们定义和实现依赖服务接口的定义。在Spring Cloud Feign的实现下,我们只需创建一个接口并用注解的方式来配置它,即可完成对服务提供方的接口绑定,简化了在使用Spring Cloud Ribbon时自行封装服务调用客户端的开发量。Spring Cloud Feign具备可插拔的注解支持,包括Feign注解和JAX-RS注解。同时,为了适应Spring的广大用户,它在Netflix Feign的基础上扩展了对Spring MVC的注解支持。这对于习惯于Spring MVC的开发者来说,无疑是一个好消息,你我这样可以大大减少学习适应它的成本。另外,对于Feign自身的一些主要组件,比如编码器和解码器等,它也以可插拔的方式提供,在有需求等时候我们以方便扩张和替换它们。
在本节中,我们将通过一个简单示例来展示Spring Cloud Feign在服务客户端定义所带来的便利。下面等示例将继续使用之前我们实现等hello-service服务,这里我们会通过Spring Cloud Feign提供的声明式服务绑定功能来实现对该服务接口的调用。
▪️首先,创建一个Spring Boot基础工程,取名为kyle-service-feign,并在pom.xml中引入spring-cloud-starter-eureka和spring-cloud-starter-feign依赖,具体内容如下所示。
▪️创建应用主类Application,并通过@EnableFeignClients注解开启Spring Cloud Feign的支持功能。
▪️定义HelloServiceFeign,接口@FeignClient注解指定服务名来绑定服务,然后再使用Spring MVC的注解来绑定具体该服务提供的REST接口。
▪️接着,创建一个RestClientController来实现对Feign客户端的调用。使用@Autowired直接注入上面定义的HelloServiceFeign实例,并在postPerson函数中调用这个绑定了hello-service服务接口的客户端来向该服务发起/hello接口的调用。
▪️后,同Ribbon实现的服务消费者一样,需要在application.properties中指定服务注册中心,并定义自身的服务名为feign-service-provider,为了方便本地调试与之前的Ribbon消费者区分,端口使用8868。
发送几次GET请求到 ,可以得到如之前Ribbon实现时一样到效果,正确返回 hi, kyle! i from 10.166.37.142:8877。依然是利用Ribbon维护了针对HELLO-SERVICE-PROVIDER的服务列表信息,并且通过轮询实现了客户端负载均衡。而与Ribbon不同到是,通过Feign只需定义服务绑定接口,以声明式的方法,优雅而简单地实现了服务调用。
现实系统中的各种业务接口要比上一节复杂得多,我们会再HTTP的各个位置传入各种不同类型的参数,并且再返回响应的时候也可能是一个复杂的对象结构。再本节中,我们将详细介绍Feign中的不同形式参数的绑定方法。
再开始介绍Spring Cloud Feign的参数绑定之前,我们先扩张以下服务提供者hello-service-provider。增加下面这些接口,其中包含带有Request参数的请求、带有Header信息的请求、带有RequestBody的请求以及请求响应体中是一个对象的请求。
在完成了对hello-service-provider的改造之后,下面我们开始在快速入门示例的kyle-service-feign应用中实现这些新增的绑定。
这里一定要注意,再定义各参数绑定时,@RequestParam、@RequestHeader等可以指定参数名称的主角,它们的value千万不能少。在Spring MVC程序中,这些注解会根据参数名来作为默认值,但是在Feign中绑定参数必须通过value属性来指明具体的参数名,不然会抛出==IllegalStateException==异常,value属性不能为空。
在完成上述改造之后,启动服务注册中心、两个hello-service-privider服务以及我们改造的kyle-service-feign。通过发送GET请求到== ,通过发送POST请求到== ,请求触发HelloServiceFeign对新增接口的调用。终,我们会获得如下图的结果,代表接口绑定和调试成功。
由于Spring Cloud Feign的客户端负载均衡是通过Spring Cloud Ribbon实现的,所以我们可以直接配置Ribbon客户端的方式来自定义各个服务客户端调用参数。那么我们如何使用Spring Cloud Feign的工程中使用Ribbon的配置呢?
全局配置的方法非常简单,我们可以直接使用ribbon.<key>=<value>的方式来设置ribbon的各项默认参数。如下:
大多数情况下,我们对于服务调用的超时时间可能会根据实际服务的特性做一些调整,所以仅仅进行个性化配置的方式与使用Spring Cloud Ribbon时的配置方式是意义的,都采用<client>.ribbon.key=value的格式进行设置。但是,这里就有一个疑问了,<cleint>所指代的Ribbon客户端在那里呢?
回想一下,在定义Feign客户端的时候,我们使用了@FeignClient注解。在初始化过程中,Spring Cloud Feign会根据该注解的name属性或value属性指定的服务名,自动创建一个同名的Ribbon客户端。如下:
Spring Cloud Ribbon默认负载均衡策略是轮询策略,不过该不一定满足我们的需要。Ribbon一共提供了7种负载均衡策略,如果我们需要ZoneAvoidanceRule,首先要在application.properties文件中添加配置,如下所示:
不过,只是添加了如上配置,还无法实现负载均衡策略的更改。我们还需要实例化该策略,可以在应用主类中直接加入IRule实例的创建,如下:
想要深入了解Ribbon的原理,或者想详细了解7种负载均衡策略的,可以参考我另一篇博客《Ribbon详解》,我会在博客下面给出链接。
从前两节来看在Spring Boot工程中使用Feign,非常的便利。不过实际生产中,在微服务的初期只能从次要系统开始进行改造,可能很多系统由于历史原因仍然是非Spring Boot的工程,然后这些系统如何使用微服务?如何使用注册中心?如何进行负载均衡呢?
▪️首先我们在kyle-service-feign创建调用接口OldSystemPostFeign和OldSystemGetFeign,然后使用feign注解提供的相关注解,包含@RequestLine、@Param、@HeaderParam、@Headers等,主要提供了请求方法、请求参数、头信息参数等*作。
▪️我们需要脱离Spring Boot和Spring Cloud的支持,使用feign原生的一些东西。在进行Feign封装之前我们需要一些额外的组件,比如编码器。新增组件依赖如下所示:
▪️我们需要一个feign-clientproperties文件,来进行ribbon相关的参数配置,配置如下:
▪️到目前为止,相关要素已经准备好了,接下来需要feign和ribbon的封装了。我们需要创建OldSystemFeignClientConfiguration类,作用是加载feign-client.properties文件,并创建一个附带负载均衡器的RibbonClient,然后封装出一个附带Jackson编解码器的FeignClient,如下所示:
▪️然后我需要一个测试类FeignClientTest,测试以上3个接口,然后将结果输出到控台如下所示:
▪️在完成上述改造之后,启动测试类FeignClientTest,获得如下的结果,说明调用使用了负载均衡。
细心的同学会发现,非Spring Boot使用feign调用根本没有使用到注册中心的服务发现。在此我提供一个思路,我们可以调用代理微服务,再由代理进行服务发现。那么这个代理服务应该具备哪些功能和作用呢?我将会在下一篇博客详细讲述Netflix公司的API**组件zuul,它承担路由转发,拦截过滤,流量控制等功能。
▪️第一次请求失败
原因:由于spring的懒加载机制导致大量的类只有在真正使用的才会真正创建,由于默认的熔断超时时间(1秒)过短,导致第一次请求很容易失败,特别互相依赖复杂的时候。
解决方法:提升熔断超时时间和ribbon超时时间,配置如下:
▪️ Feign的Http Client
Feign在默认情况下使用的是JDK原生URLConnection发送HTTP请求,没有连接池,但是对每个地址会保持一个长连接,即利用HTTP的persistence connection。我们可以用Apache的HTTP Client替换Feign原始的http client,从而获取连接池、超时时间等与性能息息相关的控制能力。Spring Cloud从Brixtion.SR5版本开始支持这种替换,首先在项目中声明Apcahe HTTP Client和feign-httpclient依赖,然后在application.properties中添加:
▪️如何实现在feign请求之前进行*作
feign组件提供了请求*作接口RequestInterceptor,实现之后对apply函数进行重写就能对request进行修改,包括header和body*作。
▪️请求压缩
Spring Cloud Feign支持对请求和响应进行GZIP压缩,以减少通信过程中的性能损耗。我们只需通过下面两个参数设置,就能开启请求与响应的压缩功能:
同时,我们还能对请求压缩做一些更细致的设置,比如下面的配置内容指定了压缩的请求数据类型,并设置了压缩的大小下限,只有超过这个大小的请求才会对其进行压缩。
上述配置的feignpression.request.nime-types和feignpression.requestmin-request-size均为默认值。
▪️日志配置
Spring Cloud Feign在构建被@FeignClient注解修饰的服务客户端时,会为每一个客户端都创建一个feign的请求细节。可以在 application.properties文件中使用logging.level.<FeignClient>的参数配置格式来开启指定Feign客户端的DEBUG日志,其中<FeignClient>为Feign客户端定义捷克队完整路径,比如针对本博文中我们实现的HelloServiceFeign可以如下配置开启:
但是,只是添加了如上配置,还无法实现对DEBUG日志的输出。这时由于Feign客户端默认对Logger.Level对象定义为NONE级别,该界别不会记录任何Feign调用过程中对信息,所以我们需要调整它对级别,针对全局对日志级别,可以在应用主类中直接假如Logger.Level的Bean创建,具体如下:
在调整日志级别为FULL之后,我们可以再访问第一节的 接口,这是我们在kyle-service-feign的控制台中可以看到类似下面的请求详细的日志:
对于Feign的Logger级别主要有下面4类,可根据实际需要进行调整使用。
▪️负载均衡异常
当我们只是对一个微服务进行调用的时候,Ribbon提供的支持好像没什么问题。不过在我们进行多个微服务调用时会产生异常,这也是大多数人忽略的。
情景描述:2个应用B和C,在A中使用feign client调用B和C;测试结果,假如先调用B,再调用C都是有效的,但是再调用B就是无效的;(B,C先后顺序改变,都会产生这个bug)
解决方法:在主启动类使用注解@RibbonClient,进行RibbonClient配置,如下所示:
看不懂是吗?不要紧,我下面详细讲解一下,先看一下我们之前的非Spring Boot工程中封装FeignClient:
OldSystemPostFeign只是一个接口,Feign为什么需要使用接口来调用远程接口?原因就是使用JDK动态代理,我们可以去看Feign是如何进行处理。
二、Spring***MVC***配置文件讲解
使用@Controller定义一个控制器
使用@RequestMapping映射请求
使用@RequestParam绑定请求参数到方法参数
使用@ModelAttribute提供一个从模型到数据的链接
使用@SessionAttributes指定存储在会话中的属性
<context:annotation-config/>
他的作用是隐式地向 Spring容器注册
AutowiredAnnotationBeanPostProcessor、
CommonAnnotationBeanPostProcessor、
PersistenceAnnotationBeanPostProcessor、
RequiredAnnotationBeanPostProcessor
这 4个BeanPostProcessor。
例如:
如果想使用@ Resource、@ PostConstruct、@ PreDestroy等注解就必须声明CommonAnnotationBeanPostProcessor。
如果想使用@PersistenceContext注解,就必须声明PersistenceAnnotationBeanPostProcessor的Bean。
如果你想使用@Autowired注解,那么就必须事先在 Spring容器中声明 AutowiredAnnotationBeanPostProcessor Bean。传统声明方式如下:
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
如果想使用@Required的注解,就必须声明RequiredAnnotationBeanPostProcessor的Bean。同样,传统的声明方式如下:
<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"/>
记得,使用注解一般都会配置扫描包路径选项
<context:component-scan base-package=”XX.XX”/>
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/dispatcherServlet-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
这个配置常常见于web.xml文件中
<load-on-startup>1</load-on-startup>是启动顺序,让这个Servlet随Servletp容器一起启动。
<url-pattern>*.do</url-pattern>会拦截*.do结尾的请求。
<servlet-name>dispatcherServlet</servlet-name>这个Servlet的名字是dispatcherServlet,可以有多个DispatcherServlet,是通过名字来区分的。每一个DispatcherServlet有自己的WebApplicationContext上下文对象。同时保存的ServletContext中和Request对象中,关于key,以后说明。
在DispatcherServlet的初始化过程中,框架会在web应用的 WEB-INF文件夹下寻找名为[dispatcherServlet]-servlet.xml的配置文件,生成文件中定义的bean。
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/dispatcherServlet-servlet.xml</param-value>
</init-param>
指明了配置文件的文件名,不使用默认配置文件名,而使用springMVC.xml配置文件。
其中<param-value>**.xml</param-value>这里可以使用多种写法
1、不写,使用默认值:/WEB-INF/<servlet-name>-servlet.xml
2、<param-value>/WEB-INF/classes/springMVC.xml</param-value>
3、<param-value>classpath*:springMVC-mvc.xml</param-value>
4、多个值用逗号分隔
springMVC-mvc.xml配置文件片段讲解
<context:annotation-config/>
<!--自动扫描的包名-->
<context:component-scan base-package="com.iflysse"/>
<!--默认的注解映射的支持-->
<mvc:annotation-driven/>
<!--视图解释类-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/><!--可为空,方便实现自已的依据扩展名来选择视图解释类的逻辑-->
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
</bean>
<mvc:annotation-driven/>是一种简写形式,完全可以手动配置替代这种简写形式,简写形式可以让初学都快速应用默认配置方案。<mvc:annotation-driven/>会自动注册DefaultAnnotationHandlerMapping与AnnotationMethodHandlerAdapter两个bean,是spring MVC为@Controllers分发请求所必须的。
并提供了:数据绑定支持,@NumberFormatannotation支持,@DateTimeFormat支持,@Valid支持,读写XML的支持(JAXB),读写JSON的支持(Jackson)。
后面,我们处理响应ajax请求时,就使用到了对json的支持。
后面,对action写JUnit单元测试时,要从spring IOC容器中取DefaultAnnotationHandlerMapping与AnnotationMethodHandlerAdapter两个bean,来完成测试,取的时候要知道是<mvc:annotation-driven/>这一句注册的这两个bean。
<!-- json支持-->
<bean id="mappingJacksonHttpMessageConverter"
class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="objectMapper" ref="commonObjectMapper"/>
<property name="supportedMediaTypes">
<list>
<value>text/html;charset=UTF-8</value>
</list>
</property>
</bean>
<!-- ObjectMapper json转换-->
<bean id="commonObjectMapper" class="cn.starit.util.CommonObjectMapper"/>
三、spring shiro注解配置不生效
•@Controller
•@Service
•@Autowired
•@RequestMapping
•@RequestParam
•@ModelAttribute
•@Cacheable
•@CacheFlush
•@Resource
•@PostConstruct
•@PreDestroy
•@Repository
•@Component(不推荐使用)
•@Scope
•@SessionAttributes
•@InitBinder
•@Required
•@Qualifier
@Controller
•例如
@Controller
public class SoftCreateController extends SimpleBaseController{}
•或者
@Controller("softCreateController")
•说明
@Controller负责注册一个bean到spring上下文中,bean的ID默认为类名称开头字母小写
@Service
•例如
@Service
public class SoftCreateServiceImpl implements ISoftCreateService{}
•或者
@Service("softCreateServiceImpl")
•说明
@Service负责注册一个bean到spring上下文中,bean的ID默认为类名称开头字母小写
@Autowired
•例如
@Autowired
private ISoftPMService softPMService;
•或者
@Autowired(required=false)
private ISoftPMService softPMService= new SoftPMServiceImpl();
•说明
@Autowired根据bean类型从spring上线文中进行查找,注册类型必须唯一,否则报异常。与@Resource的区别在于,@Resource允许通过bean名称或bean类型两种方式进行查找@Autowired(required=false)表示,如果spring上下文中没有找到该类型的bean时,才会使用new SoftPMServiceImpl();
@Autowired标注作用于 Map类型时,如果 Map的 key为 String类型,则 Spring会将容器中所有类型符合 Map的 value对应的类型的 Bean增加进来,用 Bean的 id或 name作为 Map的 key。
@Autowired还有一个作用就是,如果将其标注在 BeanFactory类型、ApplicationContext类型、ResourceLoader类型、ApplicationEventPublisher类型、MessageSource类型上,那么 Spring会自动注入这些实现类的实例,不需要额外的*作。
@RequestMapping
•类
@Controller
@RequestMapping("/bbtForum.do")
public class BbtForumController{
@RequestMapping(params="method=listBoardTopic")
public String listBoardTopic(int topicId,User user){}
}
•方法
@RequestMapping("/softpg/downSoftPg.do")
@RequestMapping(value="/softpg/ajaxLoadSoftId.do",method= POST)
@RequestMapping(value="/osu/product/detail.do", params=, method=POST)
•说明
@RequestMapping可以声明到类或方法上
•参数绑定说明
如果我们使用以下的 URL请求:
topicId URL参数将绑定到 topicId入参上,而 userId和 userName URL参数将绑定到 user对象的 userId和 userName属性中。和 URL请求中不允许没有 topicId参数不同,虽然 User的 userId属性的类型是基本数据类型,但如果 URL中不存在 userId参数,Spring也不会报错,此时 user.userId值为 0。如果 User对象拥有一个 dept.deptId的级联属性,那么它将和 dept.deptId URL参数绑定。
@RequestParam
•参数绑定说明
@RequestParam("id")
listBoardTopic(@RequestParam("id")int topicId,User user)中的 topicId绑定到 id这个 URL参数,那么可以通过对入参使用@RequestParam注解来达到目的
@RequestParam(required=false):参数不是必须的,默认为true
@RequestParam(value="id",required=false)
请求处理方法入参的可选类型
• Java基本数据类型和 String
默认情况下将按名称匹配的方式绑定到 URL参数上,可以通过@RequestParam注解改变默认的绑定规则
• request/response/session
既可以是 Servlet API的也可以是 Portlet API对应的对象,Spring会将它们绑定到Servlet和 Portlet容器的相应对象上
• org.springframework.web.context.request.WebRequest
内部包含了 request对象
• java.util.Locale
绑定到 request对应的 Locale对象上
• java.io.InputStream/java.io.Reader
可以借此访问 request的内容
• java.io.OutputStream/ java.io.Writer
可以借此*作 response的内容
•任何标注了@RequestParam注解的入参
被标注@RequestParam注解的入参将绑定到特定的 request参数上。
• java.util.Map/ org.springframework.ui.ModelMap
它绑定 Spring MVC框架中每个请求所创建的潜在的模型对象,它们可以被 Web视图对象访问(如 JSP)
•命令/表单对象(注:一般称绑定使用 HTTP GET发送的 URL参数的对象为命令对象,而称绑定使用HTTP POST发送的 URL参数的对象为表单对象)
它们的属性将以名称匹配的规则绑定到 URL参数上,同时完成类型的转换。
而类型转换的规则可以通过@InitBinder注解或通过 HandlerAdapter的配置进行调整
• org.springframework.validation.Errors/ org.springframework.validation.BindingResult
为属性列表中的命令/表单对象的校验结果,注意检验结果参数必须紧跟在命令/表单对象的后面
• org.springframework.web.**nd.support.SessionStatus
可以通过该类型 status对象显式结束表单的处理,这相当于触发 session清除其中的通过@SessionAttributes定义的属性
请求处理方法返回值的可选类型
• void
此时逻辑视图名由请求处理方法对应的 URL确定,如以下的方法:
@RequestMapping("/welcome.do")
public void welcomeHandler(){}
对应的逻辑视图名为“ welcome”
• String
此时逻辑视图名为返回的字符,如以下的方法:
@RequestMapping(method= RequestMethod.GET)
public String setupForm(@RequestParam("ownerId") int ownerId, ModelMap model){
Owner owner= this.clinic.loadOwner(ownerId);
model.addAttribute(owner);
return"ownerForm";
}
对应的逻辑视图名为“ ownerForm”
• org.springframework.ui.ModelMap
和返回类型为 void一样,逻辑视图名取决于对应请求的 URL,如下面的例子:
@RequestMapping("/vets.do")
public ModelMap vetsHandler(){
return new ModelMap(this.clinic.getVets());
}
对应的逻辑视图名为“ vets”,返回的 ModelMap将被作为请求对应的模型对象,可以在 JSP视图页面中访问到。
• ModelAndView
当然还可以是传统的 ModelAndView。
@ModelAttribute
•作用域:request
•例如
@RequestMapping("/base/userManageCooper/init.do")
public String handleInit(@ModelAttribute("queryBean") ManagedUser sUser,Model model,){
•或者
@ModelAttribute("coopMap")//将coopMap返回到页面
public Map<Long,CooperatorInfo> coopMapItems(){}
•说明
@ModelAttribute声明在属性上,表示该属性的value来源于model里"queryBean",并被保存到model里@ModelAttribute声明在方法上,表示该方法的返回值被保存到model里
@Cacheable和@CacheFlush
•@Cacheable:声明一个方法的返回值应该被缓存
例如:@Cacheable(modelId="testCaching")
•@CacheFlush:声明一个方法是清空缓存的触发器
例如:@CacheFlush(modelId="testCaching")
•说明
要配合缓存处理器使用,参考:
@Resource
•例如
@Resource
private DataSource dataSource;// inject the bean named'dataSource'
•或者
@Resource(name="dataSource")
@Resource(type=DataSource.class)
•说明
@Resource默认按bean的name进行查找,如果没有找到会按type进行查找,
此时与@Autowired类似
在没有为@Resource注解显式指定 name属性的前提下,如果将其标注在 BeanFactory类型、ApplicationContext类型、ResourceLoader类型、ApplicationEventPublisher类型、MessageSource类型上,那么 Spring会自动注入这些实现类的实例,不需要额外的*作。此时 name属性不需要指定(或者指定为""),否则注入失败;
@PostConstruct和@PreDestroy
•@PostConstruct
在方法上加上注解@PostConstruct,这个方法就会在Bean初始化之后被Spring容器执行
(注:Bean初始化包括,实例化Bean,并装配Bean的属性(依赖注入))。
•@PreDestroy
在方法上加上注解@PreDestroy,这个方法就会在Bean被销毁前被Spring容器执行。
@Repository
•与@Controller、@Service类似,都是向spring上下文中注册bean,不在赘述。
@Component(不推荐使用)
•@Component
@Component是所有受Spring管理组件的通用形式,Spring还提供了更加细化的注解形式:@Repository、@Service、@Controller,它们分别对应存储层Bean,业务层Bean,和展示层Bean。
目前版本(2.5)中,这些注解与@Component的语义是一样的,完全通用,在Spring以后的版本中可能会给它们追加更多的语义。所以,我们推荐使用@Repository、@Service、@Controller来替代@Component。
@Scope
•例如
@Scope("session")
@Repository()
public class UserSessionBean implementsSerializable{}
•说明
在使用XML定义Bean时,可以通过bean的scope属性来定义一个Bean的作用范围,
同样可以通过@Scope注解来完成
@Scope中可以指定如下值:
singleton:定义bean的范围为每个spring容器一个实例(默认值)
prototype:定义bean可以被多次实例化(使用一次就创建一次)
request:定义bean的范围是http请求(springMVC中有效)
session:定义bean的范围是http会话(springMVC中有效)
global-session:定义bean的范围是全局http会话(portlet中有效)
@SessionAttributes
•说明
Spring允许我们有选择地指定 ModelMap中的哪些属性需要转存到 session中,
以便下一个请求属对应的 ModelMap的属性列表中还能访问到这些属性。
这一功能是通过类定义处标注@SessionAttributes注解来实现的。
@SessionAttributes只能声明在类上,而不能声明在方法上。
•例如
@SessionAttributes("currUser")//将ModelMap中属性名为currUser的属性
@SessionAttributes()
@SessionAttributes(types= User.class)
@SessionAttributes(types=)
@SessionAttributes(types=,value=)
@InitBinder
•说明
如果希望某个属性编辑器仅作用于特定的 Controller,
可以在 Controller中定义一个标注@InitBinder注解的方法,
可以在该方法中向 Controller了注册若干个属性编辑器
•例如
@InitBinder
public void initBinder(WebDataBinder **nder){
SimpleDateFormat dateFormat= new SimpleDateFormat("yyyy-MM-dd");
dateFormat.setLenient(false);
**nder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
}
@Required
•例如
@required
public setName(String name){}
•说明
@ required负责检查一个bean在初始化时其声明的 set方法是否被执行,当某个被标注了@Required的 Setter方法没有被调用,则 Spring在解析的时候会抛出异常,以提醒开发者对相应属性进行设置。@Required注解只能标注在 Setter方法之上。因为依赖注入的本质是检查 Setter方法是否被调用了,而不是真的去检查属性是否赋值了以及赋了什么样的值。如果将该注解标注在非 setXxxx()类型的方法则被忽略。
@Qualifier
•例如
@Autowired
@Qualifier("softService")
private ISoftPMService softPMService;
•说明
使用@Autowired时,如果找到多个同一类型的bean,则会抛异常,此时可以使用@Qualifier("beanName"),明确指定bean的名称进行注入,此时与@Resource指定name属性作用相同。