1、为什么使用注解配置 Spring?
答:XML 配置文件,非编程语言语法,无法调试,使用注解配置代码,更容易定位问题,所以注解可以替代 XML 配置文件。
2、配置步骤:
注意:Eclipse 需要先安装 STS 插件,或者使用 STS 开发工具创建项目。
(1)导入包
注意:在基于注解的配置中,还要多拷贝一个 aop 的 jar 包。如下图:
(2)在类的根路径下创建一个任意名称的 xml 文件(不能是中文)
注意:基于注解整合时,Spring 配置文件导入约束时需要多导入一个 context 名称空间下的约束。
(3)创建一个服务类
创建一个测试的服务类,并且加入使用 @Component 注解,声明该类允许注入到 Spring 容器
1 package com.mgy.service; 2 3 import org.springframework.stereotype.Component; 4 5 //1.使用注解配置,需要启动,就是将创建对象的类表示为组件类 6 @Component 7 public class CustomerService { 8 9 public void save(){ 10 System.out.println("-保存数据-"); 11 } 12 13 }
(4)在 Spring 的配置文件中加入扫描注解
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:context="http://www.springframework.org/schema/context" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd 6 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd"> 7 <!-- 声明扫描包以及子包的类。如果发现有组件注解的类,就创建对象,并加入到容器 --> 8 <context:component-scan base-package="com.mgy"></context:component-scan> 9 </beans>
(5)测试调用代码
1 package com.mgy.test; 2 3 import org.springframework.context.support.ClassPathXmlApplicationContext; 4 5 import com.mgy.service.CustomerService; 6 7 public class CustomerServiceTest { 8 9 public static void main(String[] args) { 10 ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("classpath:bean.xml"); 11 12 CustomerService customerService = context.getBean("customerService",CustomerService.class); 13 customerService.save(); 14 context.close(); 15 } 16 }
3、Spring 常用注解说明:
(1)用于对象的注解
我们将用于被扫描创建对象的注解,统称为组件注解。
组件注解包括:@Component、@Controller、@Service、@Repository
在 context 的 jar 包里面:
问题:从功能上这四个组件注解有什么区别?
答:功能上没有任何区别,只是概念上不一样。
组件注解的功能都是标识类为注解的组件类,启动 Spring 框架的程序时,将声明了注解的类的对象注入到 Spring 容器里面。意味着,只有加了这四个注解任何一个注解的类,在程序启动的时候,Spring 就通过配置文件指定的路径将该路径下的所有带组件注解的类创建对象并且放在容器里面。功能类似原来配置文件的 <bean> 标签。
问题:明明一个 @Component 注解就可以满足了扫描的需要,为什么要四个呢?
答:其实 Spring 第一版注解的实现(Spring 2.5),就是使用一个 @Component。从 3.0 以后,作者认为根据分层的需要,把它拆成了四个。为了可以让开发人员,可见即可得,一看到注解,立即知道类的性质,所以分成了四个。
@Controller:用于声明表示层的组件注解
@Service:用于声明服务层的组件注解
@Repository:用于声明持久层的组件注解
@Component:用于声明三层以外的组件注解
问题:那么,这四个注解交换使用会报错吗,如:持久层,放@Service 注解?
答:处理 @Controller 在 SpringMVC 里面有强制的要求,SpringMVC 的表示层必须使用@Controller 组件注解。其他情况,用乱了是不会报错的,不过我们必须不能用乱。不遵守规范,很难和别人一起开发。
(2)用于依赖注入的注解
回顾:XML 配置文件使用 <property name="" ref="" > 实现注入的,通过注解也可以实现。
① @Autowired 注解
作用:用于给引用注入容器的对象。
属性:request:指定注入的对象是否允许为空,如果 required=true。表示不可以为空。
使用 @Autowired 注入的三种情况
第一种:在属性上面注入
1 package cn.mgy.action; 2 3 import org.springframework.beans.factory.annotation.Autowired; 4 import org.springframework.stereotype.Controller; 5 6 import cn.mgy.service.CustomerService; 7 8 //表示层使用@Controller 9 //如果组件注解不声明对象名,默认使用默认命名法, 10 //所谓的默认命名就是,将类的首字符小写作为类的对象名 11 //组件注解 12 //属性 value:作用用于指定该类对象的自定义对象名 13 @Controller(value="customerAction") 14 public class CustomerAction { 15 16 @Autowired 17 private CustomerService customerService=null; 18 19 /* 20 public void setCustomerService(CustomerService customerService) { 21 this.customerService = customerService; 22 }*/ 23 24 public void save(){ 25 System.out.println("-保存客户-CustomerAction"); 26 customerService.save(); 27 } 28 29 }
第二种:在方法上面注入 <property>
1 package cn.mgy.action; 2 3 import org.springframework.beans.factory.annotation.Autowired; 4 import org.springframework.stereotype.Controller; 5 6 import cn.mgy.service.CustomerService; 7 8 //表示层使用@Controller 9 //如果组件注解不声明对象名,默认使用默认命名法, 10 //所谓的默认命名就是,将类的首字符小写作为类的对象名 11 //组件注解 12 //属性 value:作用用于指定该类对象的自定义对象名 13 @Controller(value="customerAction") 14 public class CustomerAction { 15 16 17 private CustomerService customerService=null; 18 19 //注意,如果将@Autowired方法方法上面,意思就是将对象注入到该的方法的参数 20 //意味着:Spring会自动根据参数的CustomerService类型匹配容器中对应的对象给它 21 //注意:能够使用@Autowired注解的方法是必须有参数的 22 @Autowired 23 public void setCustomerService(CustomerService customerService) { 24 //问题:加了@Autowired的方法哎启动的时候是否执行了? 25 //答:如果该方法没有执行,那么this.customerService的对象从哪里来呢? 26 //加了@Autowired在启动项目的时候是必须自动执行的 27 System.out.println("-setCustomerService已经被执行-"); 28 this.customerService = customerService; 29 } 30 31 public void save(){ 32 System.out.println("-保存客户-CustomerAction"); 33 customerService.save(); 34 } 35 36 }
第三种:在构造方法上面注入 <constructor-arg>
1 package cn.mgy.service.impl; 2 3 import org.springframework.beans.factory.annotation.Autowired; 4 import org.springframework.stereotype.Service; 5 6 import cn.mgy.dao.CustomerDAO; 7 import cn.mgy.service.CustomerService; 8 9 //业务层,使用 @Service 10 @Service 11 public class CustomerServiceImpl implements CustomerService{ 12 13 14 //如果构造方法加入@Autowired,Spring框架会自动匹配容器中是否有对应参数类的对象,将对象赋予构造方法的参数 15 //如果要使用@Autowired给构造方法注入对象,该构造方法必须要有参数 16 @Autowired 17 public CustomerServiceImpl(CustomerDAO customerDAO) { 18 super(); 19 this.customerDAO = customerDAO; 20 } 21 22 private CustomerDAO customerDAO; 23 24 @Override 25 public void save(){ 26 System.out.println("-保存客户-CustomerService"); 27 customerDAO.save(); 28 } 29 30 }
(3)@Qualifier 注解
作用:用于指定注入的对象名,使用 @Autowired 注入对象时,@Autowired 没有指定对象名的属性,只能通过 @Qualifier 字段给容器中对象命名。
属性:value:指定注入 Spring 容器中对应对象的对象名
(4)@Resource 注解
@Resource 注解是 Spring 框架支持 Sun 官方制定的 JSR-250 标准注入对象的实现。
JSR-250 就是 Sun 公司制定,对注入的对象的标准。
@Resource 功能等同于 @Autowired + @Qualifier,等同配置文件标签 <property name="" ref="" >
@Resource 注解:用于给引用注入容器的对象,可以通过 name 属性制定对象名
问题:在现实开发中,没有强制要求使用 @Autowired 或者 @Resource,两个都可以使用。但是因为 @Autowired 是 Spring 自带的机制。所以建议使用 @Autowired.
注意事项:@Resource 只能注入方法和属性,不能注入构造方法
问题:学习各种注解的关键点在哪里?
第一:必须要指定注解对应的功能含义
第二:通过查看注解的声明,理解注解可以存放的位置以及有哪些属性。
要学会通过注解声明的 @Target 的类型来分析,注解可以放的位置(重点)
注入注解所在的包的位置:
除了@Resource注解是 Java 官方的标准,内置在 JDK 里面以外,Spring 内置实现的注解声明放在 Spring-beans-4.2.9.RELEASE.jar 里面。如图所示:
(5)@Value 注解 <value>
@Value:只能设置 标量类型 = 基础数据类型 + 包装类 + String
@Value 注解:注入基本数据类型以及它们的包装类和 String 类型数据的,支持 ${} 注入 Properties 文件的键值对,等同于 <property name="" value="${Key}">。
属性:value:注入基本数据类型和 String 类型数据的。
4、示例代码 IoC 的实现
通过注解的方式,实现 Spring 框架 IoC(控制反转)的配置
(1)导入框架需要的 jar 包
(2)创建配置文件 bean.xml
创建一个配置文件,加入指定扫描的包的路径
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:context="http://www.springframework.org/schema/context" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd 6 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd"> 7 <!-- 声明扫描包以及子包的类。如果发现有组件注解的类,就创建对象,并加入到容器 --> 8 <context:component-scan base-package="com.mgy"></context:component-scan> 9 </beans>
(3)编写类的内容代码
通过注解的方式,实现将类注入到容器里面。从 DAO 层开始。
持久层的实现
1 package com.mgy.dao; 2 3 public interface CustomerDAO { 4 5 public void save(); 6 7 }
1 package com.mgy.dao.impl; 2 3 import org.springframework.stereotype.Repository; 4 5 import com.mgy.dao.CustomerDAO; 6 //持久层,使用的组件注解为@Repository 7 @Repository 8 public class CustomerDAOImpl implements CustomerDAO { 9 10 @Override 11 public void save(){ 12 System.out.println("-保存客户数据-dao"); 13 } 14 15 }
业务层的实现
1 package com.mgy.service; 2 3 public interface CustomerService { 4 5 /** 6 * 声明一个注册方法 7 */ 8 void reigster(); 9 }
1 package com.mgy.service.impl; 2 3 import org.springframework.beans.factory.annotation.Autowired; 4 import org.springframework.stereotype.Service; 5 6 import com.mgy.dao.CustomerDAO; 7 import com.mgy.service.CustomerService; 8 //业务层,使用Service组件注解 9 @Service 10 public class CustomerServiceImpl implements CustomerService{ 11 //通过@Autowired给customerDAO引用注入Spring容器的对象 12 @Autowired 13 private CustomerDAO customerDAO; 14 15 16 public void reigster(){ 17 System.out.println("--注册客户-service"); 18 customerDAO.save(); 19 } 20 21 }
表示层的实现
1 package com.mgy.action; 2 3 import org.springframework.beans.factory.annotation.Autowired; 4 import org.springframework.beans.factory.annotation.Qualifier; 5 import org.springframework.stereotype.Controller; 6 7 import com.mgy.service.CustomerService; 8 9 //表示层,使用@Controller组件注解 10 @Controller 11 public class CustomerAction { 12 //使用@Resource注解将Spring容器的对象注入给customerService引用 13 @Resource 14 private CustomerService customerService; 15 16 public void register() { 17 System.out.println("-客户注册-action"); 18 customerService.reigster(); 19 } 20 21 }
(4)测试代码
1 package com.mgy.test; 2 3 import org.springframework.context.support.ClassPathXmlApplicationContext; 4 5 import com.mgy.action.CustomerAction; 6 7 public class CustomerServiceTest { 8 9 public static void main(String[] args) { 10 //CustomerService cs=new CustomerService(); 11 //读取bean.xml配置文件,根据bean.xml的配置创建对象,放在容器里面 12 ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("classpath:bean.xml"); 13 //从容器中获得customerAction对象 14 CustomerAction customerAction = context.getBean("customerAction",CustomerAction.class); 15 //调用注册方法 16 customerAction.register(); 17 //关闭容器 18 context.close(); 19 } 20 }
(5)@Qualifier 注解的使用
在 IoC 的实现的代码的 Service 层增加一个同样继承 CustomerService 的类发现,再运行程序竟然报错了。
为什么呢?
首先我们必须先理解 Spring 创建对象到注入对象的原理。
--------- Spring 对象创建流程
① 在启动 Spring 框架的时候,框架先根据 <context:component-scan base-package="com.mgy" > 去获得该包下的所有的类名。
② 通过反射技术,根据类名获得类结构的组件注解,如果有就创建对象,如果没有就忽略该类。
③ 创建对象后将对象放在 Spring 容器里面,如果不在组件注解的 value 指定对象名,使用的是默认命名法:就是取类名的首字母修改为小写为对象名,如:CustomerDaoImpl 的对象名为 customerDaoImpl
---------- Spring 对象注入流程
Spring 将容器里面的对象注入给声明的引用
① 首先匹配引用的类型在容器中是否存在兼容类型的对象。就是匹配引用的类型是否是父类或者相同类型的类,如果匹配的类型的对象只有一个直接将对象注入到该引用。
② 如果匹配的类型的对象不是唯一的,将引用的属性名匹配 Spring 容器对象的对象名,如果找到对象名一样的,就注入相同对象名的对象。
根据 Spring 对象注入流程,如果出现两个类型一样的对象,必须要指定对应的对象名。指定对象名的方式有两种:
第一种:在组件注入使用 value="对象名" 指定
1 package com.mgy.service.impl; 2 3 import org.springframework.beans.factory.annotation.Autowired; 4 import org.springframework.stereotype.Service; 5 6 import com.mgy.dao.CustomerDAO; 7 import com.mgy.service.CustomerService; 8 //指定注入到容器里面时,对象的对象名 9 @Service(value="customerService") 10 public class CustomerServiceImpl implements CustomerService{ 11 12 @Autowired 13 private CustomerDAO customerDAO; 14 15 16 public void reigster(){ 17 System.out.println("--注册客户-service"); 18 customerDAO.save(); 19 } 20 }
第二种:在注入对象给引用时指定
通过 @Qualifier 指定
现有两个继承 CustomerService 的类
指定 customerServiceImpl 类的对象
1 package com.mgy.action; 2 3 import org.springframework.beans.factory.annotation.Autowired; 4 import org.springframework.beans.factory.annotation.Qualifier; 5 import org.springframework.stereotype.Controller; 6 7 import com.mgy.service.CustomerService; 8 9 10 @Controller 11 public class CustomerAction { 12 //等同使用@Autowired+@Qualifier指定注入的对象名 13 // @Resource(name="customerServiceImpl") 14 @Autowired 15 //注入指定对象名为customerServiceImpl的对象 16 @Qualifier(value="customerServiceImpl") 17 private CustomerService customerService; 18 19 public void register() { 20 System.out.println("-客户注册-action"); 21 customerService.reigster(); 22 } 23 }
(6)@Value 注解的使用
@Value 注解:注入基本数据类型和 String 类型数据的
配置文件
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:context="http://www.springframework.org/schema/context" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd 6 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd"> 7 <bean name="now" class="java.util.Date"></bean> 8 <!-- 声明扫描包以及子包的类。如果发现有组件注解的类,就创建对象,并加入到容器 --> 9 <context:component-scan base-package="com.mgy"></context:component-scan> 10 11 </beans>
CustomerService 类
1 package com.mgy.service; 2 3 import java.util.Date; 4 5 import javax.annotation.Resource; 6 7 import org.springframework.beans.factory.annotation.Value; 8 import org.springframework.stereotype.Service; 9 10 @Service 11 public class CustomerService { 12 //注入基本数据类型和String类型数据的 13 @Value(value="18") 14 private int age; 15 @Value(value="张三") 16 private String name; 17 @Resource(name="now") 18 private Date birthDate; 19 20 21 public void reigster(){ 22 System.out.println("姓名:"+name); 23 System.out.println("年龄:"+age); 24 System.out.println("生日:"+birthDate); 25 26 } 27 28 }
测试代码
1 package com.mgy.test; 2 3 import org.springframework.context.support.ClassPathXmlApplicationContext; 4 5 import com.mgy.service.CustomerService; 6 7 public class CustomerServiceTest { 8 9 public static void main(String[] args) { 10 ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("classpath:bean.xml"); 11 12 CustomerService customerService = context.getBean("customerService",CustomerService.class); 13 customerService.reigster(); 14 context.close(); 15 } 16 17 }
5、用于设置 Spring 容器对象生命周期的注解
Spring 是通过 @Scope 注解来指定对象的生命周期的。
scope:用于设置对象的作用范围,可选参数如下:
singleton:单例
对象出生:当程序加载配置文件创建容器时创建
对象存活:只要容器存在,一直存活
对象死亡:应用停止,容器销毁,对象死亡
prototype:多例(原型对象)
对象出生:当程序加载配置文件创建容器时创建
对象存活:只要对象被使用,一直存活
对象死亡:对象长时间不用,会被 Java 垃圾回收机制回收
request:web 项目中,Spring 将创建的对象放在 request 作用域中
session:web 项目中,Spring 将创建的对象放在 session 作用域中
(1)@Scope 注解
作用:指定 bea 的作用范围
属性:value:指定范围的值
取值:singleton、prototype、request、session
(2)示例代码 --- 获得单例对象
所谓的单例对象,就是每次从 Spring 容器获得的对象就是同一个对象。默认不加 @Scope 或者声明 @Scope(value="singleton") 都是单例
组件类:
1 package com.mgy.service; 2 3 import org.springframework.context.annotation.Scope; 4 import org.springframework.stereotype.Service; 5 6 @Service 7 //默认不写,或者声明value="singleton" 8 //都是声明当前类的对象为一个单例对象 9 @Scope(value="singleton") 10 public class CustomerService { 11 12 public void reigster(){ 13 System.out.println("-客户注册-"); 14 } 15 }
测试代码:
1 package com.mgy.test; 2 3 import org.springframework.context.support.ClassPathXmlApplicationContext; 4 5 import com.mgy.service.CustomerService; 6 7 public class CustomerServiceTest { 8 //如果两次获得的对象是同一个内存地址,说明是单例对象 9 public static void main(String[] args) { 10 11 ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("bean.xml"); 12 //获得对象1 13 CustomerService customerService = context.getBean("customerService",CustomerService.class); 14 customerService.reigster(); 15 System.out.println(customerService); 16 //获得对象2 17 CustomerService customerService1 = context.getBean("customerService",CustomerService.class); 18 System.out.println(customerService1); 19 context.close(); 20 } 21 22 }
测试结果
两个获得的对象是相同的,说明该类产生的对象是单例对象
(3)示例代码 ---- 获得原型对象
所谓的原型对象,就是每次从 Spring 容器中获得的对象都是重新创建的
组件类
1 package com.mgy.service; 2 3 import org.springframework.context.annotation.Scope; 4 import org.springframework.stereotype.Service; 5 6 @Service 7 //声明value="prototype" 8 //就是当前类的对象是一个原型对象 9 @Scope(value="prototype") 10 public class CustomerService { 11 12 public void reigster(){ 13 System.out.println("-客户注册-"); 14 } 15 16 }
测试结果
两次获得对象内存不同,说明声明周期设置为 prototype
(4)和生命周期相关的注解
① @PostConstruct 注解 等同于 <bean init-method="">
作用:用于指定初始化方法
② @PreDestroy 注解 等同于 <bean destroy-method="">
作用:用于指定销毁方法
示例代码:
组件类
1 package com.mgy.service; 2 3 import javax.annotation.PostConstruct; 4 import javax.annotation.PreDestroy; 5 6 import org.springframework.context.annotation.Scope; 7 import org.springframework.stereotype.Service; 8 9 @Service 10 //默认不写,或者声明value="singleton" 11 //都是声明当前类唯一个单列对象 12 @Scope(value="singleton") 13 public class CustomerService { 14 //对象初始方法 15 @PostConstruct 16 public void init(){ 17 System.out.println("初始化必须调用该方法"); 18 } 19 20 21 public void reigster(){ 22 System.out.println("-客户注册-"); 23 } 24 25 //对象注销前,必须调用该方法 26 @PreDestroy 27 public void destroy(){ 28 System.out.println("注销前必须调用该方法"); 29 } 30 31 }
测试代码
1 package com.mgy.test; 2 3 import org.springframework.context.support.ClassPathXmlApplicationContext; 4 5 import com.sxt.service.CustomerService; 6 7 public class CustomerServiceTest { 8 9 public static void main(String[] args) { 10 11 ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("bean.xml"); 12 //容器启动后,调用初始化init()方法 13 CustomerService customerService = context.getBean("customerService",CustomerService.class); 14 customerService.reigster(); 15 //容器关闭前调用 destroy()注销方法 16 context.close(); 17 System.out.println("-容器关闭后-"); 18 } 19 20 }
6、纯注解配置
用 @Configuration 注解和 @ComponentScan 注解替代 XML文件和 <context:component-scan base-package="cn.mgy"></context:component-scan> ,就可以完全不用 XML 就可以进行配置了。
替换 XML 配置文件的 @Configuration 注解 |
@Configuration 配置类注解,在纯注解配置中,类加了该注解,就意味着该类是 Spring 的配置类。该类的功能就是用来替代原来的 XML 配置文件。 作用:用于指定当前类是一个 Spring 配置类,当创建容器时会从该类上加载注解。获取容器时需要使用 AnnotationConfigApplicationContext(有 @Configuration 注解的类.class) |
@ComponentScan 注解 |
@ComponentScan 注解扫描类,作用就是配置扫描 Spring 组件类的路径。功能等同原来配置文件的 <context:component-scan base-package="cn.mgy"></context:component-scan> 作用:用于指定 Spring 在初始化容器时要扫描的包。作用和在 Spring 的 XML 配置文件中的:<context:component-scan base-package="cn.mgy"></context:component-scan> 是一样的。 属性:basePackage:用于指定要扫描的包,和该注解中的 value 属性作用一样 |
@PropertySource 注解 |
作用:用于加载 .properties 文件中的配置。例如我们配置数据源时,可以把连接数据库的信息写到 properties 配置文件中,就可以使用此注解指定 properties 配置文件的位置。等同于 XML 配置文件中的:<context:property-placeholder file-encoding="UTF-8" location="classpath:sys.properties" /> 属性:value[]:用于指定 properties 文件位置。如果是在类路径下,需要写上 classpath |
@Bean 注解 |
作用:该注解只能写在方法上,使用此方法创建一个对象,并且放入 Spring 容器中。它就相当于我们之前在 XML 配置中介绍的 <bean 标签> 属性:name:给当前 @Bean 注解方法创建的对象指定一个名称(即 bean 的 id) |
@Import 注解 |
作用:用于导入其他配置类,在引入其他配置类时,可以不用再写 @Configuration 注解。当然,写上也没有问题。 属性:value[]:用于指定其他配置类的字节码 |
(1)简单入门
需求:通过一个简单的入门示例,实现创建一个配置类使用 @Configuration 注解和 @ComponentScan 注解替换 XML 文件
配置步骤:
① 创建一个 Java 项目,导入 jar 包
② 编写组件类的代码
组件类 CustomerService 类
1 package com.mgy.service; 2 3 import org.springframework.beans.factory.annotation.Value; 4 import org.springframework.stereotype.Component; 5 6 @Component 7 public class CustomerService { 8 9 @Value(value="1") 10 private String id; 11 @Value(value="张三") 12 private String name; 13 @Value(value="123456") 14 private String password; 15 16 public void save(){ 17 System.out.println("-保存数据-"); 18 System.out.println("编号"+id); 19 System.out.println("姓名:"+name); 20 System.out.println("密码:"+password); 21 } 22 23 }
③ 编写配置类代码
通过该配置类的代码替换掉 Spring 配置文件
1 package com.mgy.config; 2 3 import org.springframework.context.annotation.ComponentScan; 4 import org.springframework.context.annotation.Configuration; 5 6 //1.使用@Configuration声明该类为一个Spring配置类 7 @Configuration 8 //2.使用@ComponentScan指定扫描的包路径 9 @ComponentScan(basePackages="com.mgy") 10 public class BeanConfig { 11 12 }
④ 编写测试代码
1 package com.mgy.test; 2 3 import org.springframework.context.annotation.AnnotationConfigApplicationContext; 4 5 import com.mgy.config.BeanConfig; 6 import com.mgy.service.CustomerService; 7 8 public class CustomerServiceTest { 9 10 public static void main(String[] args) { 11 //注意:读取注解配置类的容器类为AnnotationConfigApplicationContext 12 AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext(BeanConfig.class); 13 14 CustomerService customerService = context.getBean("customerService",CustomerService.class); 15 customerService.save(); 16 context.close(); 17 } 18 19 }
测试结果
7、Spring 整合 Junit
以上的代码,测试类都是通过 main 方法来测试的。当然我们最专业的单元测试工具是 Junit。你可以简单地将 main 方法换成 Junit。代码如下:
1 package com.mgy.test; 2 import org.junit.Test; 3 import org.springframework.context.support.ClassPathXmlApplicationContext; 4 import com.mgy.service.CustomerService; 5 public class CustomerServiceTest { 6 7 //简单实用Junit单元测试工具 8 @Test 9 public void customerService() { 10 11 ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("classpath:bean.xml"); 12 CustomerService customerService = context.getBean("customerService",CustomerService.class); 13 customerService.save(); 14 context.close(); 15 } 16 }
但 Spring 框架也通过 spring-test-4.2.9.RELEASE.jar 包对 Junit 单元测试工具进行了整合。如果使用 spring-test-4.2.9.RELEASE.jar 来实现 Junit 单元测试,可以不用 ClassPathXmlApplicationContext 和 AnnotationConfigApplicationContext 获得容器对象。可以直接使用容器中的对象。
下面就通过 spring-test-4.2.9.RELEASE.jar 来实现 Spring 框架使用 Junit 单元测试工具。
(1)测试基于 XML 的配置
就是使用 spring-test-4.2.9.RELEASE.jar 的功能对 XML 配置文件配置的 Spring 项目进行单元测试。
① 创建项目导入包
② 编写一个简单的 CustomerService 类
1 package com.mgy.service; 2 3 import java.util.Date; 4 5 public class CustomerService { 6 7 private int age; 8 private String name; 9 private Date birthDate; 10 11 public void setAge(int age) { 12 this.age = age; 13 } 14 15 public void setName(String name) { 16 this.name = name; 17 } 18 19 public void setBirthDate(Date birthDate) { 20 this.birthDate = birthDate; 21 } 22 23 public void reigster(){ 24 System.out.println("姓名:"+name); 25 System.out.println("年龄:"+age); 26 System.out.println("生日:"+birthDate); 27 } 28 }
③ 编写 Spring 配置文件
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd "> 5 <bean name="now" class="java.util.Date"></bean> 6 <bean name="customerService" class="com.mgy.service.CustomerService"> 7 <!-- 一个property标签匹配一个set方法 --> 8 <property name="name" value="张三"></property> 9 <property name="age" value="15"></property> 10 <property name="birthDate" ref="now"></property> 11 </bean> 12 13 </beans>
④ Junit 测试
1 package com.mgy.test; 2 3 import org.junit.Test; 4 import org.junit.runner.RunWith; 5 import org.springframework.beans.factory.annotation.Autowired; 6 import org.springframework.test.context.ContextConfiguration; 7 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 8 9 import com.mgy.service.CustomerService; 10 //指定Junit之前测试之前,加入Spring框架启动的逻辑代码 11 @RunWith(SpringJUnit4ClassRunner.class) 12 //指定Spring启动必须的配置文件 13 //注意:配置文件通过locations指定 14 @ContextConfiguration(locations="classpath:bean.xml") 15 public class CustomerServiceTest { 16 17 //获得Spring容器中的对象 18 @Autowired 19 private CustomerService customerService; 20 21 22 //直接调用@Autowired获得容器对象 23 @Test 24 public void reigster() { 25 customerService.reigster(); 26 27 } 28 29 }
(2)测试基于纯注解的配置
就是通过 spring-test-4.2.9.RELEASE.jar 对纯注解配置的 Spring 项目进行单元测试
① 创建一个项目并导入包
② 编写一个简单的组件类
package com.mgy.service; import java.util.Date; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; @Service public class CustomerService { @Value("12") private int age; @Value("张三") private String name; @Autowired @Qualifier(value="now") private Date birthDate; public void setAge(int age) { this.age = age; } public void setName(String name) { this.name = name; } public void setBirthDate(Date birthDate) { this.birthDate = birthDate; } public void reigster(){ System.out.println("姓名:"+name); System.out.println("年龄:"+age); System.out.println("生日:"+birthDate); } }
③ 编写一个配置类
1 package com.mgy.config; 2 3 import java.util.Date; 4 5 import org.springframework.context.annotation.Bean; 6 import org.springframework.context.annotation.ComponentScan; 7 import org.springframework.context.annotation.Configuration; 8 9 @Configuration 10 @ComponentScan(basePackages="com.sxt") 11 public class BeanConfig { 12 13 @Bean 14 public Date now() { 15 return new Date(); 16 } 17 }
④ 使用 Junit 测试
1 package com.mgy.test; 2 3 import org.junit.Test; 4 import org.junit.runner.RunWith; 5 import org.springframework.beans.factory.annotation.Autowired; 6 import org.springframework.test.context.ContextConfiguration; 7 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 8 9 import com.mgy.config.BeanConfig; 10 import com.mgy.service.CustomerService; 11 //指定Junit之前测试之前,加入Spring框架启动的逻辑代码 12 @RunWith(SpringJUnit4ClassRunner.class) 13 //指定Spring启动必须的配置文件 14 //注意:配置类通过classes指定 15 @ContextConfiguration(classes=BeanConfig.class) 16 public class CustomerServiceTest { 17 18 //获得Spring容器中的对象 19 @Autowired 20 private CustomerService customerService; 21 22 //直接调用@Autowired获得容器对象 23 @Test 24 public void reigster() { 25 customerService.reigster(); 26 27 } 28 }
8、总结
(1)首先要知道注解的配置与 XML 的配置功能一样
(2)理解注解的配置与 XML 的配置分别有什么作用
------ 组件注解
作用:用于声明类为一个注解类,Spring 会在启动的时候,根据 <context:component-scan /> 扫描的包的范围,将这些加了组件注解的类创建对象,并且放在容器里面
@Component、@Controller、@Service、@Repository
--- 依赖注入(不用 new)
@Autowired 作用:用于依赖注入,将容器里面的对象注入到对应的属性、构造方法的参数、方法的参数 等同于 <property name="属性名" ref=""> <constractor-arg name="" ref="">
@Qualifier 作用:在容器中同一个类型的对象出现多个,可以通过 @Qualifier 指定对象名来获得指定的对象
@Resource(name="对象名") 等同于 @Autowired + @Qualifier
@Resource 的作用也是用于注入对象的,是 Java JSR250 标准的支持。注意:该注解不能将对象注入到构造方法的参数上面
@Value 作用:如果注入的不是对象,而是一个标量类型,可以使用 @Value
--- 声明周期
@Scope 作用:用于指定创建的对象的生命周期,是单例、原型
注意:@Scope 如果放在方法上面,必须要和 @Bean 注解结合使用
@PostConstruct 作用:用于指定初始化方法
@PreDestroy 作用:用于指定容器销毁之前执行的方法
--- 纯注解的支持(替换配置文件)
@Configuration 作用:用于声明类是一个配置类
@ComponentScan 作用:用于扫描组件类创建对象到容器 <context:component-scan>
@PropertySource 作用:用于对 Properties 文件的支持 <context:property-placeholder>
@Bean 作用:用于将非组件类的对象加入到 Spring 容器中 <bean>
@Import(了解)作用:用于导入其他的配置类的配置
--- 对 Junit 的整合的支持(了解)
@RunWith(SpringJUnit4ClassRunner.class) 作用:用于指定 Junit 测试之前,加入 Spring 框架启动的逻辑代码
@ContextConfiguration 作用:用于指定整合时配置文件(locations="classpath:bean.xml")或文件类(classes=BeanConfig.class)