首页 > Python基础教程 >
-
java教程之Spring (2)框架
Spring第二天笔记
1. 使用注解配置Spring入门
1.1. 说在前面
学习基于注解的IoC配置,大家脑海里首先得有一个认知,即注解配置和xml配置要实现的功能都是一样的,都是要降低程序间的耦合。只是配置的形式不一样。
关于实际的开发中到底使用xml还是注解,每家公司有着不同的使用习惯。所以这两种配置方式我们都需要掌握。
基于注解配置的方式也已经逐渐代替xml。所以我们必须要掌握使用注解的方式配置Spring。
1.2. 配置步骤
注意:Eclipse需要先安装了STS插件,或者使用STS开发工具创建项目。
1.2.1. 第一步:拷贝必备jar包到工程的lib目录。
注意:在基于注解的配置中,我们还要多拷贝一个aop的jar包。如下图:
|
1.2.2. 第二步:在类的根路径下创建一个任意名称的xml文件(不能是中文)
|
注意:基于注解整合时,Spring配置文件导入约束时需要多导入一个context名称空间下的约束
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd "> </beans> |
1.2.3. 第二步:创建一个服务类
创建一个测试的服务类,并且加入使用@Component注解,声明该类允许注入到Spring容器
package com.zj.spring.service;
import org.springframework.stereotype.Component;
//1.使用注解配置,需要将启动是就创建对象的类表示为组件类 @Component public class CustomerService {
public void save(){ System.out.println("-保存数据-"); }
}
|
1.2.4. 第四步在spring的配置文件加入扫描注解
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 声明扫描包以及子包的类。如果发现有组件注解的类,就创建对象,并加入到容器 --> <context:component-scan base-package="cn.zj.spring"></context:component-scan> </beans> |
1.2.5. 第五步:测试调用代码
package com.zj.spring.test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.zj.spring.service.CustomerService;
public class CustomerServiceTest {
public static void main(String[] args) { //CustomerService cs=new CustomerService(); ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
CustomerService customerService = context.getBean("customerService",CustomerService.class); customerService.save(); context.close(); } }
|
--测试结果,如果可以调用服务方法,测试成功
|
1.2.6. 设置注解扫描的组件的名称
默认情况下, 被注解@Component 扫描的类的名称就是当前类名的首字母小写名称,开发者可以自定义组件的名称
/* 使用注解方式配置IOC @Component 说明当前类被Spring管理,Spring框架启动的时候就会创建此类的对象 设置当前Bean的名称 默认当前Bean的名称就是简单类名的 首字母小写 customerService value 属性可以自定义组件的名称 等价于 <bean id/name="bean名称"> @Component(value="service") 简写,可以省略value @Component("service")
*/ @Component("service") public class CustomerService { public void save() { System.out.println("-保存数据-"); } } |
2. Spring常用注解说明
2.1. 用于对象的注解-IOC相关注解
我们将用于被扫描创建对象的注解,统称为组件注解。
组件包括:@Component,@Controller,@Service,@Repository。
组件注解的功能都是标识类为注解的组件类,启动Spring框架的程序时,声明将这些组件类注入到Spring容器里面。意味着,只有加了这四个注解任何一个注解的类,在程序启动的时候,Spring就通过配置文件指定的路径将该路径下的所有带组件注解的类创建对象并且放在容器里面。
功能类似原来配置文件的<bean>标签
问题:明明一个@Component注解就可以满足了扫描的需要,为什么要有四个呢?
答:其实Spring第一版注解的实现(spring 2.5),就是使用一个@Component。从3.0以后,作者认为根据分层的需要,把它拆成了四个。为了可以让开发人员,可见即可得,一看到注解,立即知道类的性质。所以分成了四个
@Controller:用于声明表示层的组件注解
@Service:用于声明服务层的组件注解
@Repository:用于声明持久层的组件注解
@Component:用于声明三层以外的组件注解
问题:那么,这四个注解交换使用会报错吗。如:持久层,我放@Service标记。
答:处理@Controller在SpringMVC里面有强制的要求,SpringMVC的表示层必须使用@Controller组件注解。其他情况,用乱了是不会报错的,不过我们必须不能用乱。不遵守规范,不然别人无法跟你一起开发了。
2.1.1. @Scope用于设置对象的生命周期注解
Xml配置需要配置对象的作用范围
<bean id="someBean" class="..." scope="作用范围"></bean> |
如果使用注解配置bean,那么bean的作用范围也需要使用注解配置
@Scope("作用范围")
singleton
|
单例 ,在Spring IoC容器中仅存在一个Bean实例 (默认的scope) |
prototype |
多例 ,每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时 ,相当于执行new XxxBean(): |
request |
用于web开发,将Bean放入request范围 ,request.setAttribute("xxx") , 在同一个request 获得同一个Bean
|
session |
用于web开发,将Bean 放入Session范围,在同一个Session 获得同一个Bean |
package cn.zj.spring.controller;
import javax.annotation.Resource;
import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Controller;
import cn.zj.spring.service.CustomerService; @Controller("customerController") @Scope("prototype") public class CustomerController {
//直接字段注入,不需要setter方法 //@Resource //按照类型注入 @Resource(name="customerService")//类型+id private CustomerService customerService;
public void save() { //调用服务的save方法 customerService.save(); } }
|
在开发中主要使用 scope="singleton"、 scope="prototype"
对于MVC中的Action/Controller使用prototype类型,其他使用singleton
2.1.2. @PostConstruct @PreDestroy初始化和销毁方法注解
在xml配置中可以配置对象的初始化方法和销毁方法
<bean id="someBean" class="cn.zj.spring.domain.SomeBean" init-method="init" destroy-method="destory"></bean> |
如果使用注解配置bean,那么bean的作用范围也需要使用注解配置
@PostConstruct // 相当于<bean init-method="init" /> public void init() { System.out.println("初始化方法执行了"); } @PreDestroy// 相当于<bean destroy-method="destory" /> public void destory() { System.out.println("销毁方法执行了"); } |
2.2. 用于依赖注入的注解
回顾:XML配置文件使用<property name=”” ref=””>实现注入的。通过注入注解也可以实现。
Spring提供了两套注解可以解决依对象依赖注入的方案
1,@Autowired +@Qualifier():是Spring定义的标签
2,@Resouce:是J2EE的规范
2.2.1. @Autowired注解
@Autowired注解:用于给引用注入容器的对象。
- @Autowired标签贴在字段或者setter方法上
- 默认情况下@Autowired标签必须要能找到对应的对象,否则报错。不过,可使用required=false来避免该问题:@Autowired(required=false)
- @Autowired找bean的方式:
(1) 首先按照依赖对象的类型找,如果找到则使用setter方法或者字段直接注入;
(2) 如果在Spring上下文中找到多个匹配的类型,再按照名字去找,如果没有匹配则报错;
(3) 可以通过使用@Qualifier("otherBean")标签来规定依赖对象按照bean的id+类型去找
使用@Autowired注入的三种情况
2.2.1.1. 在字段上面注入
package cn.zj.spring.controller;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller;
import cn.zj.spring.service.CustomerService; //表示层使用@Controller //如果组件注解不声明对象名,默认使用默认命名法, //所谓的默认命名就是,将类的首字符小写作为类的对象名 //组件注解 //属性 value:作用用于指定该类对象的自定义对象名 @Controller("customerController") public class CustomerController {
//直接字段注入,不需要setter方法 @Autowired private CustomerService customerService;
/*public void setCustomerService(CustomerService customerService) { this.customerService = customerService; }*/ public void save() { //调用服务的save方法 customerService.save(); } }
|
2.2.1.2. 在方法上面注入
package cn.zj.spring.controller;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller;
import cn.zj.spring.service.CustomerService;
//表示层使用@Controller //如果组件注解不声明对象名,默认使用默认命名法, //所谓的默认命名就是,将类的首字符小写作为类的对象名 //组件注解 //属性 value:作用用于指定该类对象的自定义对象名 @Controller(value="customerController") public class CustomerController {
private CustomerService customerService=null;
//注意,如果将@Autowired方法方法上面,意思就是将对象注入到该的方法的参数 //意味着:Spring会自动根据参数的CustomerService类型匹配容器中对应的对象给它 //注意:能够使用@Autowired注解的方法是必须有参数的 @Autowired public void setCustomerService(CustomerService customerService) { //问题:加了@Autowired的方法在启动的时候是否执行了? //答:如果该方法没有执行,那么this.customerService的对象从哪里来呢? //加了@Autowired在启动项目的时候是必须自动执行的 System.out.println("-setCustomerService已经被执行-"); this.customerService = customerService; }
public void save(){ System.out.println("-保存客户-CustomerAction"); customerService.save(); }
}
|
2.2.1.3. 在构造方法上面注入
package cn.zj.spring.controller;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Controller;
import cn.zj.spring.service.CustomService;
@Controller public class CustomController {
private CustomService service;
/* * 方式三 : 构造器注入 * 使用注解的IOC创建bean的情况下 * 默认bean中有什么样的构造器,spring就调用那个构造器去创建对应的bean对象 * 并且会自动注入 构造器中对应类型参数的对象 * * 问题: 如果构造函数的参数类型对应的bean有多个,会抛出异常 * org.springframework.beans.factory.NoUniqueBeanDefinitionException 不是唯一的bean异常 * 解决方案: 在参数前面 使用 @Qualifier("service1") 注解 * 从多个bean 获取指定 id 对应的bean即可 */ public CustomController(@Qualifier("service1") CustomService service) { this.service = service; }
public void save() { service.save(); }
}
|
2.2.2. @Qualifier注解
@Qualifier注解:用于指定注入的对象名,使用@Autowired注入对象时,@Autowired没有指定对象名的属性,只能通过@Qualifier字段容器中对象名
属性
value:指定注入Spring容器中对应对象名的对象给引用。
@Controller("customerController") public class CustomerController {
//直接字段注入,不需要setter方法 @Autowired @Qualifier(value="customerService") private CustomerService customerService;
public void save() { //调用服务的save方法 customerService.save(); } } |
2.2.3. @Resource注解
@Resource注解是Spring框架支持Sun官方制定的JSR-250标准注入对象的实现。
JSR-250就是Sun公司制定,对注入的对象的标准。
@Resource 功能等同 @Autowired + @Qualifier ,等同配置文件标签 <proprty name=”...” ref=”...”>
@Resource注解:用于给引用注入容器的对象,可以通过name属性指定对象名
注意事项:@Resource只能使用字段和setter方法,不能注入构造方法
package cn.zj.spring.controller;
import javax.annotation.Resource;
import org.springframework.stereotype.Controller;
import cn.zj.spring.service.CustomerService; @Controller("customerController") public class CustomerController {
//直接字段注入,不需要setter方法 //@Resource //按照类型注入 @Resource(name="customerService")//类型+id private CustomerService customerService;
public void save() { //调用服务的save方法 customerService.save(); } }
|
2.2.4. 依赖注入注解所在的包的位置
除了@Resource注解是Java官方的标准,内置在JDK里面以外,Spring内置实现的注解声明放在spring-beans-5.0.5.RELEASE.jar里面。如下图所示:
|