本文主要介绍四个方面:

(1) 注解版本IOC和DI

(2) Spring纯注解

(3) Spring测试

(4) SpringJDBC - Spring对数据库的操作

使用注解配置Spring入门

说在前面

学习基于注解的IoC配置,大家脑海里首先得有一个认知,即注解配置和xml配置要实现的功能都是一样的,都是要降低模块间的耦合度。仅仅只是配置的形式不一样。

关于实际的开发中到底使用xml还是注解,每家公司有着不同的使用习惯。所以这两种配置方式我们都需要掌握。

基于注解配置的方式也已经逐渐代替xml配置。所以我们必须要掌握使用注解的方式配置Spring。

配置步骤

注意:如果使用Eclipse需要先安装了STS插件,或者使用STS开发工具创建项目。本文使用IDEA进行演示。

1.2.1. 第一步:拷贝必备jar包到工程的lib目录。

注意:在基于注解的配置中,我们还要多拷贝一个aop的jar包。如下图:

基于注解配置对象容器 - 图1

1.2.2. 第二步:在类的根路径下创建一个任意名称的xml文件(不能是中文)

基于注解配置对象容器 - 图2

注意:基于注解整合时,Spring配置文件导入约束时需要多导入一个context命名空间下的约束。

  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
  6. http://www.springframework.org/schema/beans/spring-beans.xsd
  7. http://www.springframework.org/schema/context
  8. http://www.springframework.org/schema/context/spring-context.xsd">
  9. </beans>

1.2.3. 第二步:创建一个服务类

创建一个测试的服务类,并且加入使用@Component注解,声明该类允许注入到Spring容器

  1. package org.cjw.service;
  2. import org.springframework.stereotype.Component;
  3. /*
  4. 使用注解配置时,需要将Spring框架启动就创建对象的类表示为组件类
  5. 表示组件类使用@Component注解
  6. */
  7. @Component
  8. public class CustomerService {
  9. public void save() {
  10. System.out.println("-保存数据-");
  11. }
  12. }

1.2.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
  6. http://www.springframework.org/schema/beans/spring-beans.xsd
  7. http://www.springframework.org/schema/context
  8. http://www.springframework.org/schema/context/spring-context.xsd">
  9. <!-- 声明扫描包及其子包的类,如果发现有组件注解的类,就创建对象并加入到容器中去 -->
  10. <context:component-scan base-package="org.cjw" />
  11. </beans>

1.2.5. 第五步:测试调用代码

  1. package org.cjw.test;
  2. import org.cjw.service.CustomerService;
  3. import org.junit.Test;
  4. import org.springframework.context.ApplicationContext;
  5. import org.springframework.context.support.ClassPathXmlApplicationContext;
  6. public class CustomerServiceTest {
  7. @Test
  8. public void testSave() {
  9. ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  10. CustomerService customerService = context.getBean(CustomerService.class);
  11. customerService.save();
  12. }
  13. }

—测试结果,如果可以调用服务方法,测试成功。

基于注解配置对象容器 - 图3

1.2.6. 设置注解扫描的组件的名称

默认情况下,被注解@Component 扫描的类的名称就是当前类名的首字母小写名称,开发者可以自定义组件的名称。

—组件类

  1. package org.cjw.service;
  2. import org.springframework.stereotype.Component;
  3. /*
  4. 使用注解的方式配置IOC:
  5. 标注了@Component注解表示当前类被Spring管理,Spring框架启动的时候就会创建此类的对象到spring容器中去
  6. 设置当前Bean的名称:
  7. 默认当前Bean的名称就是简单类名的首字母小写(customerService)
  8. @Component注解的value属性可以自定义组件的名称,等价于<bean id/name="bean名称" />
  9. @Component(value="service")表示将bean的名称设置service
  10. 当注解的属性只有一个,并且名为value的时候,可以省略value,
  11. 即@Component(value="service")等价于@Component("service")
  12. */
  13. @Component("service")
  14. public class CustomerService {
  15. public void save() {
  16. System.out.println("-保存数据-");
  17. }
  18. }

—测试代码

  1. Test
  2. public void testSave() {
  3. ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  4. CustomerService customerService = (CustomerService) context.getBean("service");
  5. customerService.save();
  6. }

—测试结果

基于注解配置对象容器 - 图4

Spring常用注解说明

2.1. 用于对象的注解-组件注解

我们将用于被扫描创建对象的注解,统称为组件注解。

组件包括:@Controller@Service@Repository@Component

组件注解的功能就是标识那些在Spring框架启动时,需要创建对象并保存在IOC容器中的类。意味着,只有加了这四个注解中的任何一个注解的类,在Spring框架启动的时候,Spring就通过配置文件指定的路径将该路径下的所有带组件注解的类创建对象并且放在容器里面。

组件注解的功能类似原来配置文件的<bean>标签。

问题:明明一个@Component注解就可以满足了扫描的需要,为什么要有四个呢?

答:其实Spring第一版注解的实现(spring 2.5),只有@Component组件注解。从spring3.0以后,作者认为根据分层的需要,把它拆成了四个。为了可以让开发人员可见即可得,一看到注解,立即知道类的性质。所以分成了四个。

@Controller:用于声明表示层的组件注解

@Service:用于声明服务层的组件注解

@Repository:用于声明持久层的组件注解

@Component:用于声明三层以外的组件注解

问题:那么,这四个注解交换使用会报错吗。如:持久层,我放@Service标记。

答:@Controller在SpringMVC里面有强制的要求,SpringMVC的表示层必须使用@Controller组件注解。其他情况,用乱了是不会报错的,不过我们必须不能用乱。不遵守规范,不然别人就无法跟我们一起开发了。

2.1.1. @Scope用于设置对象的生命周期注解

Xml配置需要配置对象的作用范围

  1. <bean id="" class="" scope="作用域"/>

如果使用注解配置bean,那么bean的作用范围也需要使用注解配置。

@Scope(“作用范围”)

singleton:单例,在ioc容器中仅存在一个Bean实例(默认的scope)。

prototype:多例,每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时 ,相当于执行newInstance(),并且ioc容器不会管理多例对象。

request:用于web开发,将Bean放入request作用域中,request.setAttribute(“xxx”) , 在同一个request对象中获取同一个Bean。

session:用于web开发,将Bean 放入Session作用域中,在同一个Session对象中获取同一个Bean。

—组件代码

  1. @Component("customerService")
  2. @Scope("singleton")
  3. public class CustomerService {
  4. }
  5. @Service("customerService2")
  6. @Scope("prototype")
  7. public class CustomerService2 {
  8. }

—测试代码

  1. @Test
  2. public void testSave() {
  3. ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  4. CustomerService customerService = (CustomerService) context.getBean("customerService");
  5. CustomerService customerService2 = (CustomerService) context.getBean("customerService");
  6. System.out.println("singleton: " + (customerService == customerService2));
  7. CustomerService2 customerService3 = (CustomerService2) context.getBean("customerService2");
  8. CustomerService2 customerService4 = (CustomerService2) context.getBean("customerService2");
  9. System.out.println("prototype: " + (customerService3 == customerService4));
  10. }

—测试结果

基于注解配置对象容器 - 图5

在开发中主要使用 scope=”singleton”、 scope=”prototype”

对于MVC中的Action/Controller使用prototype类型,其他使用singleton。

2.1.2. @PostConstruct @PreDestroy初始化和销毁方法注解

在xml配置中可以配置对象的初始化方法和销毁方法。

  1. <bean id="someBean" class="org.cjw.pojo.SomeBean"
  2. init-method="init"
  3. destroy-method="destory"/>

如果使用注解配置bean,那么bean的作用范围也需要使用注解配置。

  1. @PostConstruct // 相当于<bean init-method="init" />
  2. public void init() {
  3. System.out.println("初始化方法执行了");
  4. }
  5. @PreDestroy// 相当于<bean destroy-method="destory" />
  6. public void destory() {
  7. System.out.println("销毁方法执行了");
  8. }

—测试代码

  1. @Test
  2. public void testXml() {
  3. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  4. context.close();
  5. }

—测试结果

基于注解配置对象容器 - 图6

用于依赖注入的注解

回顾:XML配置文件使用<property name=”” value/ref=””><constructor-arg name="" value/ref="" />实现setter注入和构造注入。通过注入注解也可以实现DI。

Spring提供了两套注解可以解决对象依赖注入的方案:

1. @Autowired +@Qualifier():是Spring定义的标签

2. @Resouce:是JavaEE的规范

2.2.1. @Autowired注解

@Autowired注解:用于标识需要依赖注入的对象属性。

  1. @Autowired注解贴在字段或者setter方法上。
  2. 默认情况下@Autowired注解必须要能找到对应的对象,否则报错。不过,可使用required=false来避免该问题:@Autowired(required=false)
  3. @Autowired找bean的方式:

(1) 首先按照依赖对象的类型找,如果只找到一个则使用字段或者setter方法直接注入。

(2) 如果在Spring上下文中找到多个匹配的类型,则再按照名字去找,如果没有匹配则报错(NoSuchBeanDefinitionException)。

(3) 可以通过使用@Qualifier(“otherBean”)注解来规定依赖对象按照类型+bean的id去找。

使用@Autowired注入的三种情况

2.2.1.1. 字段注入

  1. @Controller("customerController")
  2. public class CustomerController {
  3. // 反射字段直接注入:Field.set(obj, value);
  4. @Autowired
  5. private CustomerService customerService;
  6. public void save() {
  7. customerService.save();
  8. }
  9. }

2.2.1.2. setter方法注入

  1. @Controller("customerController")
  2. public class CustomerController {
  3. private CustomerService customerService;
  4. // 如果将@Autowired放在方法的上面,意思就是将对象注入到该方法的参数
  5. // 意味着,spring会自动根据参数类型匹配容器中对应的对象给这个方法
  6. // 能够使用@Autowired注解的方法必须是有参数的
  7. @Autowired
  8. public void setCustomerService(CustomerService customerService) {
  9. // 问题:加了@Autowired注解的方法在什么时候执行?
  10. // 加了@Autowired注解的方法在创建完spring容器之后就会立即执行
  11. System.out.println("-setCustomerService被执行了-");
  12. this.customerService = customerService;
  13. }
  14. public void save() {
  15. customerService.save();
  16. }
  17. }

2.2.1.3. 构造器注入

  1. @Controller("customerController")
  2. public class CustomerController {
  3. private CustomerService customerService;
  4. /*
  5. * 方式三 : 构造器注入
  6. * 使用注解的IOC创建bean的情况下
  7. * 默认bean中有什么样的构造器,spring就调用那个构造器去创建对应的bean对象
  8. * 并且会自动注入构造器中对应类型参数的对象
  9. *
  10. * 问题: 如果构造函数有多个,默认会无参构造
  11. * 解决方案:只提供有参构造
  12. *
  13. * 问题: 如果构造函数的参数类型对应的bean有多个,会抛出异常
  14. * org.springframework.beans.factory.NoUniqueBeanDefinitionException 不是唯一的bean异常
  15. * 解决方案: 在参数前面 使用 @Qualifier("service1") 注解
  16. * 从多个bean 获取指定 id 对应的bean即可
  17. */
  18. public CustomerController(@Qualifier("customerService") CustomerService customerService) {
  19. System.out.println("-CustomerController构造器被执行了-");
  20. this.customerService = customerService;
  21. }
  22. public void save() {
  23. customerService.save();
  24. }
  25. }

2.2.2. @Qualifier注解

@Qualifier注解:用于指定注入的对象名,使用@Autowired注入对象时,@Autowired没有指定对象名的属性,只能通过@Qualifier注解来指定对象名。

value属性:指定注入Spring容器中对应对象名的对象。

  1. @Controller("customerController")
  2. public class CustomerController {
  3. @Autowired
  4. @Qualifier("customerService")
  5. private CustomerService customerService;
  6. public void save() {
  7. customerService.save();
  8. }
  9. }

2.2.3. @Resource注解

@Resource注解是Spring框架支持Sun官方制定的JSR-250标准注入对象的实现。

JSR-250就是Sun公司制定,对注入的对象的标准。

@Resource功能等同@Autowired + @Qualifier等同配置文件标签 <proprty name="..." ref="...">

@Resource注解:用于给引用注入容器的对象,可以通过name属性指定对象名。

注意事项:@Resource只能使用字段和setter注入,不能使用构造注入

2.2.3.1. 字段注入

  1. @Controller("customerController")
  2. public class CustomerController {
  3. // 类型+id注入
  4. @Resource(name = "customerService")
  5. private CustomerService customerService;
  6. public void save() {
  7. customerService.save();
  8. }
  9. }

2.2.3.2. setter方法注入

  1. @Controller("customerController")
  2. public class CustomerController {
  3. private CustomerService customerService;
  4. // 类型+id
  5. @Resource(name = "customerService")
  6. public void setCustomerService(CustomerService customerService) {
  7. this.customerService = customerService;
  8. }
  9. public void save() {
  10. customerService.save();
  11. }
  12. }

2.2.4. @Value注解

property标签中的value属性只能注入基本数据类型、包装类型、String类型。

@Value注解:注入基本数据类型以及它们的包装类和String类型数据的,支持${}注入properties文件的键值对,等同 <proprty name="..." value="${Key}" />

2.2.4.1. 案例代码

—db.properties文件(在src路径下创建)

  1. jdbc.driverClassName=com.mysql.jdbc.Driver
  2. jdbc.url=jdbc:mysql://localhost:3306/users
  3. jdbc.username=root
  4. jdbc.password=root
  5. jdbc.macActive=10

—在applicationContext.xml配置文件中加载db.properties

  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
  6. http://www.springframework.org/schema/beans/spring-beans.xsd
  7. http://www.springframework.org/schema/context
  8. http://www.springframework.org/schema/context/spring-context.xsd">
  9. <!-- 声明扫描包及其子包的类,如果发现有组件注解的类,就创建对象并加入到容器中去 -->
  10. <context:component-scan base-package="org.cjw" />
  11. <!-- 加载classpath下的db.properties配置文件 -->
  12. <context:property-placeholder location="classpath:db.properties"/>
  13. </beans>

—UserDaoImpl代码

  1. @Repository
  2. public class UserDaoImpl {
  3. /**
  4. * @Value(value="")
  5. * 可以从Spring容器读取 .properties 配置文件内容
  6. * value :配置文件的对应的key -->使用 ${key} 获取
  7. * 程序运行中自动将 properties的key对应的value值获取出来设置给字段
  8. */
  9. @Value("${jdbc.driverClassName}")
  10. private String driverClassName;
  11. @Value("${jdbc.url}")
  12. private String url;
  13. @Value("${jdbc.username}")
  14. private String username;
  15. @Value("${jdbc.password}")
  16. private String password;
  17. @Value("${jdbc.maxActive}")
  18. private String maxActive;
  19. public void testValueAnnotation() {
  20. System.out.println("driverClassName:" + driverClassName);
  21. System.out.println("url:" + url);
  22. System.out.println("username:" + username);
  23. System.out.println("password:" + password);
  24. System.out.println("maxActive:" + maxActive);
  25. }
  26. }

—测试代码

  1. @Test
  2. public void testXml() {
  3. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  4. UserDaoImpl userDaoImpl = context.getBean(UserDaoImpl.class);
  5. userDaoImpl.testValueAnnotation();
  6. }

—测试结果

基于注解配置对象容器 - 图7

模拟注册功能(使用注解方式)

3.1. DAO层代码

  1. public interface UserDao {
  2. void register(User user);
  3. }
  4. @Repository
  5. public class UserDaoImpl implements UserDao {
  6. @Override
  7. public void register(User user) {
  8. System.out.println("dao层执行了register方法");
  9. }
  10. }

3.2. Service层代码

  1. public interface UserService {
  2. void register(User user);
  3. }
  4. @Service
  5. public class UserServiceImpl implements UserService {
  6. @Resource(name = "userDaoImpl")
  7. private UserDao userDao;
  8. @Override
  9. public void register(User user) {
  10. System.out.println("service层执行了register方法");
  11. userDao.register(user);
  12. }
  13. }

3.3. 表现层代码

  1. @Controller
  2. public class UserController {
  3. @Autowired
  4. @Qualifier("userServiceImpl")
  5. private UserService userService;
  6. public void register() {
  7. System.out.println("control层执行了register方法");
  8. User user = new User();
  9. userService.register(user);
  10. }
  11. }

3.4. 测试代码

  1. @Test
  2. public void testXml() {
  3. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  4. UserController userController = context.getBean(UserController.class);
  5. userController.register();
  6. }

3.5. 测试结果

基于注解配置对象容器 - 图8

3.6. applicationContext.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
  6. http://www.springframework.org/schema/beans/spring-beans.xsd
  7. http://www.springframework.org/schema/context
  8. http://www.springframework.org/schema/context/spring-context.xsd">
  9. <!-- 声明扫描包及其子包的类,如果发现有组件注解的类,就创建对象并加入到容器中去 -->
  10. <context:component-scan base-package="org.cjw" />
  11. </beans>

纯注解配置

4.1. 问题

我们发现,之所以我们现在离不开xml配置文件,是因为我们有一句很关键的配置:
<context:component-scan base-package="cn.zj.spring" />

如果他要是也能用注解配置,那么我们就可以脱离xml文件了。

通过@Configuration注解和@ComponentScan注解

基于注解配置对象容器 - 图9

基于注解配置对象容器 - 图10

模拟注册功能(纯注解方式)

5.1. 说明

需求:创建一个配置类使用@Configuration注解和@ComponentScan注解替换xml文件。

5.2. 第一步:创建一个Java项目

创建一个Java项目,导入必须的jar包以及编写好需要的类结构。代码目录如下:

基于注解配置对象容器 - 图11

5.3. 第二步:在classpath下创建db.properties配置文件

  1. jdbc.driverClassName=com.mysql.jdbc.Driver
  2. jdbc.url=jdbc:mysql://localhost:3306/users
  3. jdbc.username=root
  4. jdbc.password=root
  5. jdbc.maxActive=10

5.4. 第三步:编写配置类代码

—通过该配置类的代码替换掉Spring配置文件

  1. @Configuration // xml配置文件
  2. @PropertySource("classpath:db.properties") // 代替了<contenxt:property-placeholder/>
  3. @ComponentScan(basePackages = "org.cjw") // 代替了<contenxt:component-scan/>
  4. public class SpringConfig {
  5. @Value("${jdbc.driverClassName}") // 代替了<property>
  6. private String driverClassName;
  7. @Value("${jdbc.url}")
  8. private String url;
  9. @Value("${jdbc.username}")
  10. private String username;
  11. @Value("${jdbc.password}")
  12. private String password;
  13. @Value("${jdbc.maxActive}")
  14. private String maxActive;
  15. @Bean(name = "dataSource") // 代替了<bean/>
  16. public DataSource getDataSource() {
  17. DruidDataSource dataSource = new DruidDataSource();
  18. dataSource.setDriverClassName(driverClassName);
  19. dataSource.setUrl(url);
  20. dataSource.setUsername(username);
  21. dataSource.setPassword(password);
  22. dataSource.setMaxActive(Integer.valueOf(maxActive));
  23. return dataSource;
  24. }
  25. }

5.5. 第四步:编写三层代码

5.5.1. 表示层

  1. @Controller
  2. public class UserController {
  3. @Autowired
  4. @Qualifier("userServiceImpl")
  5. private UserService userService;
  6. public void register() {
  7. System.out.println("control层register方法执行了");
  8. User user = new User();
  9. userService.register(user);
  10. }
  11. }

5.5.2. 服务层

  1. public interface UserService {
  2. void register(User user);
  3. }
  4. @Service
  5. public class UserServiceImpl implements UserService {
  6. @Resource(name = "userDaoImpl")
  7. private UserDao userDao;
  8. @Override
  9. public void register(User user) {
  10. System.out.println("service层register方法执行了");
  11. userDao.register(user);
  12. }
  13. }

5.5.3. 持久层

  1. public interface UserDao {
  2. void register(User user);
  3. }
  4. @Repository
  5. public class UserDaoImpl implements UserDao {
  6. @Autowired
  7. private DataSource dataSource;
  8. @Override
  9. public void register(User user) {
  10. try {
  11. System.out.println("dao层register方法执行了");
  12. Connection conn = dataSource.getConnection();
  13. System.out.println(conn);
  14. } catch (SQLException e) {
  15. e.printStackTrace();
  16. }
  17. }
  18. }

5.6. 第五步:测试代码

  1. @Test
  2. public void testRegister() {
  3. ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
  4. UserController userController = context.getBean(UserController.class);
  5. userController.register();
  6. }

5.7. 第六步:测试结果

输出组件类调用方法的输出值,配置成功。

基于注解配置对象容器 - 图12

Spring的测试

6.1. 传统的测试

存在问题:

  1. 每个测试都要重新启动Spring容器,启动容器的开销大,测试效率低下。
  2. 不应该是测试代码管理Spring容器,应该是Spring容器在管理测试代码。

基于注解配置对象容器 - 图13

6.1.1. 正确使用Spring的测试

基于注解配置对象容器 - 图14

6.2. 如何使用Spring测试

6.2.1. 导入spring测试的jar包

基于注解配置对象容器 - 图15

Spring测试必须保证单元测试的最低版本是4.12版本,如果使用的IDE版本很低,那么IDE自带的单元测试版本可能低于4.12,那么需要开发者手动导入单元测试的jar包。

如果使用Spring测试,必须使用两个注解:

@RunWith注解:表示先启动Spring容器,把junit运行在Spring容器中。

@ContextConfiguration注解:加载资源文件,默认从src(源目录)下面加载。

6.2.2. XML方式的配置

@ContextConfiguration(value)

value属性: 读取classpath下的配置文件。

PS:只要是spring读取配置文件,都必须加上classpath:前缀。

  1. @RunWith(SpringJUnit4ClassRunner.class)
  2. @ContextConfiguration("classpath:applicationContext.xml")
  3. public class UserControllerTest {
  4. @Autowired
  5. private ApplicationContext context;
  6. public void testRegister() {
  7. UserController userController = context.getBean(UserController.class);
  8. userController.register();
  9. }
  10. }

6.2.3. 纯注解方式的配置

@ContextConfiguration(classes)

classes 属性: 读取配置类。

  1. @RunWith(SpringJUnit4ClassRunner.class)
  2. @ContextConfiguration(classes = SpringConfig.class)
  3. public class UserControllerTest {
  4. @Autowired
  5. private ApplicationContext context;
  6. public void testRegister() {
  7. UserController userController = context.getBean(UserController.class);
  8. userController.register();
  9. }
  10. }

Spring的JDBC操作

Spring框架也支持JDBC,对JDBC只进行了薄薄的一层封装。

问题: Java开发已经有JDBC,为什么Spring还要支持JDBC操作呢?

最重要的原因: Spring操作JDBC能自动管理事务。

基于注解配置对象容器 - 图16

基于注解配置对象容器 - 图17

基于注解配置对象容器 - 图18

原生的JDBC一套代码下来,很沉重,很多的代码都是相同、相似的,因此可以将这些代码进行封装,仅仅把那些复杂多变的代码交由开发者来完成,如sql语句的编写、结果集的处理,这就是SpringJDBC,仅仅只是对原生JDBC进行一层薄薄的封装、并且自动管理事务。但是结果集的处理部分还是交由开发者来完成,而且结果集的处理代码编写是非常头痛的,所以在目前javaWeb开发中,持久层的处理并没有使用SpringJDBC,而是使用半自动映射的MyBatis框架或者全自动映射的Hibernate。

7.1. 前期准备

操作数据部分使用SpringJDBC,其他部分业务逻辑代码不变。

—创建数据库 spring_jdbc

—创建数据表 t_user

  1. CREATE TABLE `t_user` (
  2. `id` int(11) NOT NULL AUTO_INCREMENT,
  3. `name` varchar(20) DEFAULT NULL,
  4. `email` varchar(50) DEFAULT NULL,
  5. PRIMARY KEY (`id`)
  6. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

—创建对应的domain对象

  1. package org.cjw.pojo;
  2. public class User {
  3. private Integer id;
  4. private String name;
  5. private String email;
  6. // 省略get、set、toString、有参构造、无参构造方法
  7. }

—创建DAO层

  1. @Repository
  2. public class UserDaoImpl implements UserDao {
  3. @Override
  4. public void save(User user) {}
  5. @Override
  6. public void delete(Integer id) {}
  7. @Override
  8. public void update(User user) {}
  9. @Override
  10. public User findById(Integer id) {
  11. return null;
  12. }
  13. }

—创建Service层

  1. @Service
  2. public class UserServiceImpl implements UserService {
  3. @Resource(name = "userDaoImpl")
  4. private UserDao userDao;
  5. @Override
  6. public void save(User user) {
  7. userDao.save(user);
  8. }
  9. @Override
  10. public void delete(Integer id) {
  11. userDao.delete(id);
  12. }
  13. @Override
  14. public void update(User user) {
  15. userDao.update(user);
  16. }
  17. @Override
  18. public User findById(Integer id) {
  19. return userDao.findById(id);
  20. }
  21. }

—测试代码(XML方式)

  1. @RunWith(SpringJUnit4ClassRunner.class)
  2. @ContextConfiguration("classpath:applicationContext.xml")
  3. public class UserServiceTest {
  4. @Autowired
  5. private UserService userService;
  6. @Test
  7. public void testSave() {
  8. User user = new User(null, "赵六", "zhaoliu@qq.com");
  9. userService.save(user);
  10. }
  11. @Test
  12. public void testDelete() {
  13. userService.delete(4);
  14. }
  15. @Test
  16. public void testUpdate() {
  17. User user = new User(2, "lisi", "lisi123123@qq.com");
  18. userService.update(user);
  19. }
  20. @Test
  21. public void testFindById() {
  22. User user = userService.findById(1);
  23. System.out.println(user);
  24. }
  25. }

—ApplicationContext.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
  6. http://www.springframework.org/schema/beans/spring-beans.xsd
  7. http://www.springframework.org/schema/context
  8. http://www.springframework.org/schema/context/spring-context.xsd">
  9. <context:property-placeholder location="classpath:db.properties"/>
  10. <bean id="dataSource"
  11. class="com.alibaba.druid.pool.DruidDataSource"
  12. init-method="init" destroy-method="close">
  13. <property name="driverClassName" value="${jdbc.driverClassName}"/>
  14. <property name="url" value="${jdbc.url}"/>
  15. <property name="username" value="${jdbc.username}"/>
  16. <property name="password" value="${jdbc.password}"/>
  17. <property name="maxActive" value="${jdbc.maxActive}"/>
  18. </bean>
  19. </beans>

—测试代码(注解方式)

  1. @RunWith(SpringJUnit4ClassRunner.class)
  2. @ContextConfiguration(classes = SpringConfig.class)
  3. public class UserServiceTest {
  4. @Autowired
  5. private UserService userService;
  6. @Test
  7. public void testSave() {
  8. User user = new User(null, "赵六", "zhaoliu@qq.com");
  9. userService.save(user);
  10. }
  11. @Test
  12. public void testDelete() {
  13. userService.delete(4);
  14. }
  15. @Test
  16. public void testUpdate() {
  17. User user = new User(2, "lisi", "lisi123123@qq.com");
  18. userService.update(user);
  19. }
  20. @Test
  21. public void testFindById() {
  22. User user = userService.findById(1);
  23. System.out.println(user);
  24. }
  25. }

—配置类SpringConfig

  1. @Configuration // xml配置文件
  2. @PropertySource("classpath:db.properties") // 代替了<contenxt:property-placeholder/>
  3. @ComponentScan(basePackages = "org.cjw") // 代替了<contenxt:component-scan/>
  4. public class SpringConfig {
  5. @Value("${jdbc.driverClassName}") // 代替了<property>
  6. private String driverClassName;
  7. @Value("${jdbc.url}")
  8. private String url;
  9. @Value("${jdbc.username}")
  10. private String username;
  11. @Value("${jdbc.password}")
  12. private String password;
  13. @Value("${jdbc.maxActive}")
  14. private String maxActive;
  15. @Bean(name = "dataSource") // 代替了<bean/>
  16. public DataSource getDataSource() {
  17. DruidDataSource dataSource = new DruidDataSource();
  18. dataSource.setDriverClassName(driverClassName);
  19. dataSource.setUrl(url);
  20. dataSource.setUsername(username);
  21. dataSource.setPassword(password);
  22. dataSource.setMaxActive(Integer.valueOf(maxActive));
  23. return dataSource;
  24. }
  25. }

7.2. JDBCTemplate模板类

Spring提供对应的模板类可以直接操作数据库。

基于注解配置对象容器 - 图19

如果使用JDBC就使用JDBCTemplate类(将数据库的基本操作方法已经封装好了,直接调用即可)。

7.2.1. 导入相关jar包

mysql-connector-java-5.x.jar:MySQL驱动包

spring-jdbc-4.3.2.RELEASE.jar:支持JDBC

spring-tx-4.3.2.RELEASE.jar:支持事务

druid1.1.9.jar:连接池

基于注解配置对象容器 - 图20

7.2.2. 配置文件配置JDBCTemplate

—Xml方式配置

  1. <!-- 配置jdbcTemplate 模板类 -->
  2. <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
  3. <!-- setter方法注入数据源 -->
  4. <property name="dataSource" ref="dataSource" />
  5. </bean>

—注解方式

  1. @Bean
  2. public JdbcTemplate getJdbcTemplate() {
  3. JdbcTemplate jdbcTemplate = new JdbcTemplate(getDataSource());
  4. return jdbcTemplate;
  5. }

7.2.3. Dao层代码

  1. @Repository
  2. public class UserDaoImpl implements UserDao {
  3. @Autowired
  4. private JdbcTemplate jdbcTemplate;
  5. @Override
  6. public void save(User user) {
  7. jdbcTemplate.update("insert into t_user (name, email) values (?, ?)", user.getName(), user.getEmail());
  8. }
  9. @Override
  10. public void delete(Integer id) {
  11. jdbcTemplate.update("delete from t_user where id = ?", id);
  12. }
  13. @Override
  14. public void update(User user) {
  15. jdbcTemplate.update("update t_user set name = ?, email = ? where id = ?", user.getName(), user.getEmail(), user.getId());
  16. }
  17. @Override
  18. public User findById(Integer id) {
  19. User user = jdbcTemplate.queryForObject("select * from t_user where id = ?", new Object[]{id}, new RowMapper<User>() {
  20. @Override
  21. public User mapRow(ResultSet rs, int i) throws SQLException {
  22. User user = new User();
  23. user.setId(rs.getInt("id"));
  24. user.setName(rs.getString("name"));
  25. user.setEmail(rs.getString("email"));
  26. return user;
  27. }
  28. });
  29. return user;
  30. }
  31. }

小结

Spring的IOC和DI的配置可以使用XML配置,也可以注解配置。

内容:使用注解配置。

  1. 注解配置IOC (控制反转,将对象的创建权交给Spring)-重点

(1) @Component 通用IOC 组件,试用任意Spring对象管理

(2) @Controller 主要在表现层使用

(3) @Service 业务层使用

(4) @Repository DAO层使用

(5) 必须在xml配置包扫描的位置<context:component-scan base-package=”cn.zj.spring”>

(6) Scope 设置对象的生命周期(作用范围)

  1. Singleton 单例 默认
  2. Prototype 多例
  3. Request Web开发一次请求有效
  4. Session Web开发一次会话有效

(7) PostConstructor 初始化方法

(8) PreDestory 销毁方法

  1. 注解配置DI (依赖注入)注入对象的属性(值,集合,引用)-重点

(1) @Autowired + @Qualifier Spring 框架提供

  1. 字段注入
  2. Setter注入
  3. 构造器注入

(2) @Resource JavaEE 官方的规范

  1. 字段注入
  2. Setter注入
  3. 没有构造器注入
  1. Spring纯注解配置-重点

纯注解配置替代xml配置,但是所有配置依然存在,只是配置方式变换成在类上面贴注解的形式(未来的趋势)—SpringBoot(纯注解)

  1. Spring测试

(1) 为了更方便的开发Spring程序

  1. SpringJDBC

(1) 优点:主要能够让Spring自动控制事务

(2) JdbcTemplate 模板类进行数据表的增删改查