springmvc注解注解@service括号中的service有什么用

在以前,我们使用Spring对一些属性进行依赖注入(DI)时,通常都是通过在配置文件中配置一个个的<bean>标签来实现,比如说这样:

但是一旦项目大了之后,如果要把所有的这些依赖关系都在配置文件中配置的话,无疑逻辑上是非常混乱的,这时我们就可以考虑使用几个常用的注解来实现依赖关系的注入。

实现依赖注入的几个常用注解分别是:

除了这几个对类的注解外,还有几个对类中属性的注解,主要目的是告诉Spring这个属性应该用那个前面已经注解过的类来实例化,它们分别是:

  • @Resource 默认按名称来装配注入,只有当找不到与名称相匹配的bean时才会按照类型来装配注入

  • @Autowired 默认按类型来装配注入,如果想按照名称来装配注入,则需要结合@Qualifier一起使用

由于@Autowired是按照类型来注入的,因此当同类型的变量有多个需要注入时,仅仅使用@Autowired就会出现问题,这时可以结合@Qualifier来使用,比如:

当然,由于@Resource这个注解有另外两个注解都有的功能,同时@Resource这个注解是基于J2EE的,而@Autowired和@Qualifier是属于Spring的,所以我们最好使用@Resource进行依赖注入,有利于减小应用与Spring的耦合

对于上面提到的这些注解的一些具体用法,接下来我将以一个具体的实例来举例说明:

1 项目结构与相关jar包:

可以看出,在上面的配置文件中定义了三个“context:component-scan”标签分别用于扫描数据访问层、业务层以及控制层的注解,其他配置不用多说

这一层只是简单定义了一个“User”模型,并没有使用到任何注解

//这里只是简单判断是否为空,实际需要查询数据库等操作

可以看出,在上面的代码中我们在类上定义了一个@Repository注解,用于表示这个类是数据访问层的,同时给它起了个名字叫“userDaoImpl”。问:为什么在实现类上添加@Repository注解而不是在UserDao接口上添加注解?

其实这个问题只要想一下我们在配置文件中使用<bean>标签是如何配置的就清楚了,比如对于这样一个bean:

我们可以发现,“class”属性这里指向的是一个具体的实现类而不是它的接口。原因很简单,我们需要的是一个具体的类来实例化或者说在其他类中也需要这样一个具体的类来进行参数注入,显然这是不能使用接口的。因此,上面为何在一个实现类上添加注解也是基于同样的道理,不信可以试试把@Repository注解从UserDaoImpl转移到UserDao这个接口上,看看项目运行时会不会报错?

在这里,UserServiceImpl这个类上面定义了一个@Service注解,表示它是业务逻辑层上的一个类,同样给它起了一个名字叫“userServiceImpl”。通过上面的代码可以看到,我们给userDao这个属性定义了一个@Resource注解,通过一个“name”属性表示引用的是一个名为“userDaoImpl”的UserDao类型的类来实例化userDao属性,毫无疑问这里指的就是上面定义了“@Repository(“userDaoImpl”)”注解的UserDaoImpl.java了

注:给属性添加了注解之后是可以不用再写对应的setter方法的

如果出现上面的控制台输出则表明注解已经配置正确了

注解 :参与代码编译,以@开头的。它是给应用程序看的,单独使用注解毫无意义,一定要跟工具一起使用,这个所谓的工具实际就是能读懂注解的应用程序 
注释 :对代码没有影响。对代码起到解释、说明的作用

spring没有采用约定优于配置的策略,spring要求显示指定搜索哪些路径下的Java文件。spring将会把合适的java类全部注册成spring Bean。

Bean实例的名称默认是Bean类的首字母小写,其他部分不变。

指定了某些类可作为Spring Bean类使用后,最好还需要让spring搜索指定路径,此时需要在spring配置文件中导入context Schema,并指定一个简单的搜索路径。

 
 
 
 
 
 

使用@Resource可以省略name属性。
修饰方法时,省略name属性,则该name值是该setter方法去掉前面的set字符串,首字母小写后得到的子串。
修饰Field时,省略name属性,则该name与该Field同名。
指定Bean实例的作用域。
@Scope:注解也可以指定Bean实例的作用域。
 
 

深刻理解该类使用了@PostConstruct修饰init方法,那么spring就会在该bean的依赖关系注入完成之后回调该方法。
 
 
 
 
 
 

如果注释掉chinese的依赖注入,那么结果如下:
 
 

 

在SpringMVC 中,控制器Controller 负责处理由DispatcherServlet 分发的请求,它把用户请求的数据经过业务处理层处理之后封装成一个Model ,然后再把该Model 返回给对应的View 进行展示。在SpringMVC 中提供了一个非常简便的定义Controller 的方法,你无需继承特定的类或实现特定的接口,只需使用@Controller 对象,它们可以通过Controller 的方法参数灵活的获取到。
@Controller 用于标记在一个类上,使用它标记的类就是一个SpringMVC Controller 对象。分发处理器将会扫描使用了该注解的类的方法,并检测该方法是否使用了@RequestMapping 注解。@Controller 只是定义了一个控制器类,而使用@RequestMapping 注解的方法才是真正处理请求的处理器。单单使用@Controller 标记在一个类上还不能真正意义上的说它就是SpringMVC 的一个控制器类,因为这个时候Spring 还不认识它。那么要如何做Spring 才能认识它呢?这个时候就需要我们把这个控制器类交给Spring 来管理。有两种方式:
 
 
2、@RequestMapping
RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
RequestMapping注解有六个属性,下面我们把她分成三类进行说明(下面有相应示例)。




1、共同点
两者都可以写在字段和setter方法上。两者如果都写在字段上,那么就不需要再写setter方法。
 
 
@Autowired注解是按照类型(byType)装配依赖对象,默认情况下它要求依赖对象必须存在,如果允许null值,可以设置它的required属性为false。如果我们想使用按照名称(byName)来装配,可以结合@Qualifier注解一起使用。如下:
 
 
 
 
注:最好是将@Resource放在setter方法上,因为这样更符合面向对象的思想,通过set、get去操作属性,而不是直接去操作属性。
@Resource装配顺序:
①如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常。
②如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常。
③如果指定了type,则从上下文中找到类似匹配的唯一bean进行装配,找不到或是找到多个,都会抛出异常。
④如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配。




5、@PathVariable
用于将请求URL中的模板变量映射到功能处理方法的参数上,即取出uri模板中的变量作为参数。如:
 
 
值表示接受的传入的参数类型。

使用时机:返回的数据不是html标签的页面,而是其他某种格式的数据时(如json、xml等)使用;
8、@Component
相当于通用的注解,当不知道一些类归到哪个层时使用,但是不建议。


 
 
中,我们可以使用@PathVariable 来标记一个Controller 的处理方法参数,表示该参数的值将使用URI 模板中对应的变量的值来赋值。
类型,像这种简单类型在进行赋值的时候Spring 是会帮我们自动转换的。
在上面的代码中我们可以看到在标记variable1 为path 变量的时候我们使用的是@PathVariable ,而在标记variable2 的时候使用的是@PathVariable(“variable2”) 。这两者有什么区别呢?第一种情况就默认去URI 模板中找跟参数名相同的变量,但是这种情况只有在使用debug 模式进行编译的时候才可以,而第二种情况是明确规定使用的就是URI 模板中的variable2 变量。当不是使用debug 模式进行编译,或者是所需要使用的变量名跟参数名不相同的时候,就要使用第二种方式明确指出使用的是URI 模板中的哪个变量。
 
 
当@RequestParam中没有指定参数名称时,Spring 在代码是debug 编译的情况下会默认取更方法参数同名的参数,如果不是debug 编译的就会报错。

的时候就不能够正常的访问到该方法,因为在@RequestMapping 的params 参数里面指定了参数param3 是不能存在的。




3、 @RequestMapping 标记的处理器方法支持的方法参数和返回类型
  1.  (1 )HttpServlet 对象,主要包括HttpServletRequest 、HttpServletResponse 和HttpSession 对象。 这些参数Spring 在调用处理器方法的时候会自动给它们赋值,所以当在处理器方法中需要使用到这些对象的时候,可以直接在方法上给定一个方法参数的申明,然后在方法体里面直接用就可以了。但是有一点需要注意的是在使用HttpSession 对象的时候,如果此时HttpSession 对象还没有建立起来的话就会有问题。
    
  2. 支持的返回类型 
    (3 )一个View 对象。这个时候如果在渲染视图的过程中模型的话就可以给处理器方法定义一个模型参数,然后在方法体里面往模型中添加值。 
    (4 )一个String 字符串。这往往代表的是一个视图名称。这个时候如果需要在渲染视图的过程中需要模型的话就可以给处理器方法一个模型参数,然后在方法体里面往模型中添加值就可以了。 
    (5 )返回值是void 。这种情况一般是我们直接把返回结果写到HttpServletResponse 中了,如果没有写的话,那么Spring 将会利用RequestToViewNameTranslator 来返回一个对应的视图名称。如果视图中需要模型的话,处理方法与返回字符串的情况相同。 
    (6 )如果处理器方法被注解@ResponseBody 标记的话,那么处理器方法的任何返回类型都会通过HttpMessageConverters 转换之后写到HttpServletResponse 中,而不会像上面的那些情况一样当做视图或者模型来处理。 
    (7 )除以上几种情况之外的其他任何返回类型都会被当做模型中的一个属性来处理,而返回的视图还是由RequestToViewNameTranslator 来决定,添加到模型中的属性名称可以在该方法上用@ModelAttribute(“attributeName”) 来定义,否则将使用返回类型的类名称的首字母小写形式来表示。使用@ModelAttribute 标记的方法会在@RequestMapping 标记的方法执行之前执行。

 


当 @ModelAttribute 标记在方法上的时候,该方法将在处理器方法执行之前执行,然后把返回的对象存放在 session 或模型属性中,属性名称可以使用 @ModelAttribute(“attributeName”) 在标记方法的时候指定,若未指定,则使用返回类型的类名称(首字母小写)作为属性名称。关于 @ModelAttribute 标记在方法上时对应的属性是存放在 session 中还是存放在模型中,我们来做一个实验,看下面一段代码。
 
 
当我们请求 /myTest/sayHello.do 的时候使用 @ModelAttribute 标记的方法会先执行,然后把它们返回的对象存放到模型中。最终访问到 sayHello 方法的时候,使用 @ModelAttribute 标记的方法参数都能被正确的注入值。执行结果如下所示:
 由执行结果我们可以看出来,此时 session 中没有包含任何属性,也就是说上面的那些对象都是存放在模型属性中,而不是存放在 session 属性中。那要如何才能存放在 session 属性中呢?这个时候我们先引入一个新的概念 @SessionAttributes ,它的用法会在讲完 @ModelAttribute 之后介绍,这里我们就先拿来用一下。我们在 MyController 类上加上 @SessionAttributes 属性标记哪些是需要存放到 session 中的。看下面的代码:
 
 
 
 


仍然没有打印出任何 session 属性,这是怎么回事呢?怎么定义了把模型中属性名为 intValue 的对象和类型为 User 的对象存到 session 中,而实际上没有加进去呢?难道我们错啦?我们当然没有错,只是在第一次访问 /myTest/sayHello.do 的时候 @SessionAttributes 定义了需要存放到 session 中的属性,而且这个模型中也有对应的属性,但是这个时候还没有加到 session 中,所以 session 中不会有任何属性,等处理器方法执行完成后 Spring 才会把模型中对应的属性添加到 session 中。所以当请求第二次的时候就会出现如下结果:




当 @ModelAttribute 标记在处理器方法参数上的时候,表示该参数的值将从模型或者 Session 中取对应名称的属性值,该名称可以通过 @ModelAttribute(“attributeName”) 来指定,若未指定,则使用参数类型的类名称(首字母小写)作为属性名称。



handler method 参数绑定常用的注解,我们根据他们处理的Request的不同内容部分分为四类:(主要讲解常用类型)






 
 




 
 


例如有如下Cookie值:
 
 





C) 该注解有两个属性: value、required; value用来指定要传入值的id名称,required用来指示参数是否必须绑定;
 
 



 
 


该注解用来绑定HttpSession中的attribute对象的值,便于在方法中的参数里使用。
该注解有value、types两个属性,可以通过名字和类型指定要使用的attribute 对象;
 
 
@ModelAttribute
该注解有两个用法,一个是用于方法上,一个是用于参数上;
用于方法上时: 通常用来在处理@RequestMapping之前,为请求绑定需要从后台查询的model;
用于参数上时: 用来通过名称对应,把相应名称的值绑定到注解的参数bean上;要绑定的值来源于:


C) 上述两种情况都没有时,new一个需要绑定的bean对象,然后把request中按名称对应的方式把值绑定到bean中。
 
 

 
 
首先查询 @SessionAttributes有无绑定的Pet对象,若没有则查询@ModelAttribute方法层面上是否绑定了Pet对象,若没有则将URI template中的值按对应的名称绑定到Pet对象的各属性上。

有了,另一个标签根本可以移除掉,因为已经被包含进去了
另外还提供了两个子标签
 

这种扫描的粒度有点太大,如果你只想扫描指定包下面的Controller或其他内容则设置use-default-filters属性为false,表示不再按照scan指定的包扫描,而是按照指定的包扫描,示例:



注意:本人尝试时无论哪种情况和都不能同时存在

在以前,我们使用Spring对一些属性进行依赖注入(DI)时,通常都是通过在配置文件中配置一个个的<bean>标签来实现,比如说这样:

但是一旦项目大了之后,如果要把所有的这些依赖关系都在配置文件中配置的话,无疑逻辑上是非常混乱的,这时我们就可以考虑使用几个常用的注解来实现依赖关系的注入。

实现依赖注入的几个常用注解分别是:

除了这几个对类的注解外,还有几个对类中属性的注解,主要目的是告诉Spring这个属性应该用那个前面已经注解过的类来实例化,它们分别是:

  • @Resource 默认按名称来装配注入,只有当找不到与名称相匹配的bean时才会按照类型来装配注入

  • @Autowired 默认按类型来装配注入,如果想按照名称来装配注入,则需要结合@Qualifier一起使用

由于@Autowired是按照类型来注入的,因此当同类型的变量有多个需要注入时,仅仅使用@Autowired就会出现问题,这时可以结合@Qualifier来使用,比如:

当然,由于@Resource这个注解有另外两个注解都有的功能,同时@Resource这个注解是基于J2EE的,而@Autowired和@Qualifier是属于Spring的,所以我们最好使用@Resource进行依赖注入,有利于减小应用与Spring的耦合

对于上面提到的这些注解的一些具体用法,接下来我将以一个具体的实例来举例说明:

1 项目结构与相关jar包:

可以看出,在上面的配置文件中定义了三个“context:component-scan”标签分别用于扫描数据访问层、业务层以及控制层的注解,其他配置不用多说

这一层只是简单定义了一个“User”模型,并没有使用到任何注解

//这里只是简单判断是否为空,实际需要查询数据库等操作

可以看出,在上面的代码中我们在类上定义了一个@Repository注解,用于表示这个类是数据访问层的,同时给它起了个名字叫“userDaoImpl”。问:为什么在实现类上添加@Repository注解而不是在UserDao接口上添加注解?

其实这个问题只要想一下我们在配置文件中使用<bean>标签是如何配置的就清楚了,比如对于这样一个bean:

我们可以发现,“class”属性这里指向的是一个具体的实现类而不是它的接口。原因很简单,我们需要的是一个具体的类来实例化或者说在其他类中也需要这样一个具体的类来进行参数注入,显然这是不能使用接口的。因此,上面为何在一个实现类上添加注解也是基于同样的道理,不信可以试试把@Repository注解从UserDaoImpl转移到UserDao这个接口上,看看项目运行时会不会报错?

在这里,UserServiceImpl这个类上面定义了一个@Service注解,表示它是业务逻辑层上的一个类,同样给它起了一个名字叫“userServiceImpl”。通过上面的代码可以看到,我们给userDao这个属性定义了一个@Resource注解,通过一个“name”属性表示引用的是一个名为“userDaoImpl”的UserDao类型的类来实例化userDao属性,毫无疑问这里指的就是上面定义了“@Repository(“userDaoImpl”)”注解的UserDaoImpl.java了

注:给属性添加了注解之后是可以不用再写对应的setter方法的

如果出现上面的控制台输出则表明注解已经配置正确了

我要回帖

更多关于 spring注解 的文章

 

随机推荐