SSM框架之Spring——Spring注解开发

目录

一、Spring配置数据源

1.1手动创建C3P0数据源

1.2手动创建Druid数据源

1.3抽取jdbc.properties文件

1.4Spring配置数据源

1.5Spring配置数据源(加载Properties配置方式)

二、Spring注解开发

2.1Spring原始注解

2.1.1Spring原始注解——实例化bean

2.1.2Spring原始注解优化

2.1.3Spring原始注解——注入普通数据类型

 2.1.4Spring原始注解——初始化方法和销毁方法

2.1.5Spring原始注解——单例多例模式

2.2Spring新注解

三、Spring整合Junit

3.1原Junit测试Spring的问题

3.2Spring集成Junit的步骤


一、Spring配置数据源

我们已经可以通过Spring创建自定义的类,但是如果想要用别的包里面的类,比如在连接数据库时需要数据源(连接池)里的类,那么首先我们就要配置数据源。

数据源是为了提高程序性能出现的,使用数据源通常有以下步骤:

  • 事先实例化数据源,初始化部分连接资源
  • 使用连接资源时从数据源中获取
  • 使用完毕后将连接资源归还给数据源

常用的数据源(连接池)有:DBCP、C3P0、BoneCP、Druid等。

1.1手动创建C3P0数据源

首先我们要导入mysql和c3p0的jar包,在pom.xml中添加依赖,

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.32</version>
</dependency>
<dependency>
    <groupId>c3p0</groupId>
    <artifactId>c3p0</artifactId>
    <version>0.9.1.2</version>
</dependency>

然后我们测试使用c3p0数据源连接mysql数据库,

//测试手动创建c3p0数据源
public void test1() throws Exception {
    ComboPooledDataSource dataSource=new ComboPooledDataSource();//创建c3p0数据源对象
    dataSource.setDriverClass("com.mysql.jdbc.Driver");//设置mysql驱动
    dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/mydb1");//设置数据库路径
    dataSource.setUser("root");//设置数据库用户名
    dataSource.setPassword("3837");//设置数据库密码
    Connection connection = dataSource.getConnection();//从数据源中获取连接
    System.out.println(connection);//检测是否获取到了连接
    connection.close();//关闭连接,还给数据源连接池中
}

把connection对象打印出来了, 

1.2手动创建Druid数据源

第一步还是在pom.xml中导入druid包的依赖,

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.10</version>
</dependency>

然后我们测试使用druid数据源连接mysql数据库,代码其实差不多,只是创建的对象不同,

//测试手动创建druid数据源
public void test2() throws Exception {
    DruidDataSource dataSource=new DruidDataSource();//创建druid数据源对象
    dataSource.setDriverClassName("com.mysql.jdbc.Driver");//设置mysql驱动
    dataSource.setUrl("jdbc:mysql://localhost:3306/mydb1");//设置数据库路径
    dataSource.setUsername("root");//设置数据库用户名
    dataSource.setPassword("3837");//设置数据库密码
    Connection connection = dataSource.getConnection();//从数据源中获取连接
    System.out.println(connection);//检测是否获取到了连接
    connection.close();//关闭连接,还给数据源连接池中
}

打印结果:

1.3抽取jdbc.properties文件

上面两种创建数据源都需要数据库的大量参数,后期如果更改数据库要修改对应的源码,所以我们将数据库里面的参数抽取成 jdbc.properties 文件,这样可以大大降低代码之间的耦合性,便于后期维护更新。

首先我们要新建一个配置文件jdbc.properties,设置好数据库的相关参数,

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mydb1
jdbc.username=root
jdbc.password=3837

然后我们在代码中读取该配置文件里的信息,并利用读取到的信息创建C3P0数据源获得数据库的连接,

//测试手动创建c3p0数据源(加载properties配置文件形式)
public void test3() throws Exception {
    //读取配置文件,获取配置文件中的信息
    ResourceBundle resourceBundle=ResourceBundle.getBundle("jdbc");//从类加载路径下找properties文件进行读取,这里不用写后缀名
    String driver=resourceBundle.getString("jdbc.driver");//获取Driver字符串
    String url=resourceBundle.getString("jdbc.url");//获取url字符串
    String username=resourceBundle.getString("jdbc.username");//获取username字符串
    String password=resourceBundle.getString("jdbc.password");//获取password字符串

    ComboPooledDataSource dataSource=new ComboPooledDataSource();//创建c3p0数据源对象
    dataSource.setDriverClass(driver);//设置mysql驱动
    dataSource.setJdbcUrl(url);//设置数据库路径
    dataSource.setUser(username);//设置数据库用户名
    dataSource.setPassword(password);//设置数据库密码
    Connection connection = dataSource.getConnection();//从数据源中获取连接
    System.out.println(connection);//检测是否获取到了连接
    connection.close();//关闭连接,还给数据源连接池中
}

打印连接结果:

1.4Spring配置数据源

上面我们都是手动创建的数据源,现在我们来看看如何让Spring帮我们自动创建数据源。

因为我们在手动创建时,首先通过无参构造获取数据源对象,然后通过set方法设置属性,这刚好和我们之前配置自定义对象的时候用到的方法相似,所以Spring同样可以帮我们创建数据源对象。

要让Spring帮我们创建,首先要在Spring的配置文件中进行配置,所以我们在pom.xml中先导入spring依赖的包,

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.0.5.RELEASE</version>
</dependency>

然后我们在src\main的resources文件夹下创建Spring的配置文件,创建C3P0数据源对象的标识id,并且使用依赖注入配置参数,

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
    <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/mydb1"></property>
    <property name="user" value="root"></property>
    <property name="password" value="3837"></property>
</bean>

然后我们测试一下获取dataSource对象,

//测试Spring自动创建c3p0数据源
public void test4() throws Exception {
    ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");//获取应用容器对象
    ComboPooledDataSource dataSource = (ComboPooledDataSource) app.getBean("dataSource");//通过Spring查找标识id获取数据源对象
    Connection connection = dataSource.getConnection();//获取数据库连接
    System.out.println(connection);//打印结果
    connection.close();//关闭连接,归还到数据源连接池中
}

打印结果如下:

1.5Spring配置数据源(加载Properties配置方式)

上面配置数据源时,数据库的一些信息我们是在applicationContext.xml中写死了,如果想要加载peoperties,需要先引入context命名空间和约束路径:

命名空间:xmlns:context="http://www.springframework.org/schema/context"
约束路径:http://www.springframework.org/schema/context                                   
         http://www.springframework.org/schema/context/spring-context.xsd

然后我们读取jdbc的配置文件到Spring内部,然后赋值给dataSource对象,

<!--加载外部的properties文件到Spring内部-->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>

<!--从Spring内部读取属性值赋给dataSource对象-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <!--我们通过"${key}"读取Spring内部的配置文件属性-->
    <property name="driverClass" value="${jdbc.driver}"></property>
    <property name="jdbcUrl" value="${jdbc.url}"></property>
    <property name="user" value="${jdbc.username}"></property>
    <property name="password" value="${jdbc.password}"></property>
</bean>

配置好了之后还是用之前的代码测试一下,

二、Spring注解开发

Spring是轻代码而重配置的框架,配置比较繁重,影响开发效率,所以注解开发是一种趋势,注解代替 xml 配置文件可以简化配置,提高开发效率。 

注解也是一种配置的方式,我们可以理解为代码里的特殊标记,这些标记可以在编译,类加载,运行时被读取,并执行相应的处理。通过注解,开发人员可以在不改变原有代码和逻辑的情况下在源代码中嵌入补充信息。

在Spring的注解开发中,我们主要分为两部分(原始注解和新注解,二者主要是出现的时间不同)

2.1Spring原始注解

Spring原始注解主要是替代<Bean>的配置,与Spring配置文件中<Bean>标签的作用相同。

注解

说明

   @Component

使用在上,用于实例化Bean

   @Controller

使用在web层类上,用于实例化Bean

   @Service

使用在service层类上,用于实例化Bean

   @Repository

使用在dao层类上,用于实例化Bean

   @Autowired

使用在字段上,用于根据类型依赖注入

   @Qualifier

结合@Autowired一起使用,用于根据名称进行依赖注入

   @Resource

相当于@Autowired+@Qualifier,按照名称进行注入

   @Value

注入普通属性

   @Scope

标注Bean的作用范围

   @PostConstruct

使用在方法上,标注该方法是Bean的初始化方法

   @PreDestroy

使用在方法上,标注该方法是Bean的销毁方法

首先我们还是创建Dao和Service层,实现接口里的方法,然后在Spring配置文件中进行配置,

<bean id="userDao" class="Dao.UserDaoImpl"></bean>
<bean id="userService" class="Service.UserServiceImpl">
    <property name="userDao" ref="userDao"></property>
</bean>

这是传统的xml配置方法,我们来看看如何使用注解替代这种方式。

2.1.1Spring原始注解——实例化bean

使用注解进行开发时,需要在applicationContext.xml配置组件扫描,作用是指定哪个包及其子包下的Bean需要进行扫描以便识别使用注解配置的类、字段和方法。简单来说,就是告诉Spring我哪个包写了注解,你去帮我解析解析。

<!--配置组件扫描-->
<context:component-scan base-package="Dao"></context:component-scan>
<context:component-scan base-package="Service"></context:component-scan>

然后我们在UserDaoImpl和UserServiceImpl中使用注解的方法进行Bean的实例化,

  • @Component("beanID")对当前注解的对象进行Bean实例化,id标识为beanID
  • @Autowired:对当前注解的字段设置依赖注入方式,方式为自动注入
  • @Qualifier("beanID"):对当前注解的字段设置注入的对象,该对象的id标识为beanID
package Dao;

import org.springframework.stereotype.Component;

//<bean id="userDao" class="Dao.UserDaoImpl"></bean>
@Component("userDao")//这里的userDao对应的就是bean标签中的id
public class UserDaoImpl implements UserDao {
    public void save() {
        System.out.println("saving........");
    }
}
package Service;

import Dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

//<bean id="userService" class="Service.UserServiceImpl"></bean>
@Component("userService")//这里的userService对应的就是bean标签中的id
public class UserServiceImpl implements UserService {
    //<property name="userDao" ref="userDao"></property>
    @Autowired//设置userDao字段依赖注入方式为自动注入
    @Qualifier("userDao")//对userDao字段设置需要注入的对象,这里我们需要注入UserDao对象,其id标识为userDao
    private UserDao userDao;

    public void save() {
        userDao.save();
    }
}

注解就可以不用对变量实现set方法,直接在需要赋值的变量上面加注解,然后我们运行测试类,

2.1.2Spring原始注解优化

在上面的例子中,我们给UserDaoImpl和UserServiceImpl两个对象实例化Bean都用了同一个注解@Component,这样可读性不强,不知道这两个对象属于哪一层。

Spring为了区分不同的对象,创建了三个衍生的注解,其作用和@Component相同,唯一不同是提示当前注解的类处于什么层:

  • @Controller:使用在web层类上,用于实例化Bean
  • @Service:使用在service层类上,用于实例化Bean
  • @Repository:使用在dao层类上,用于实例化Bean

我们可以将UserDaoImpl的注解替换为@Repository,UserServiceImpl的注解替换为@Service

我们还可以直接对字段userDao只保留一个注解@Autowired,删除注解@Qualifier

@Autowired//设置userDao字段依赖注入方式为自动注入
private UserDao userDao;

由于此时没有使用注解 @Qualifier 来设置注入的具体对象,自动注入会在Spring容器中找该字段类型UserDao类型的Bean对象进行注入。所以程序还是可以自动运行。

这种自动注入的方式对应了我们之前getBean()方法里传入字节码的方式,而使用注解 @Qualifier 来设置注入的具体对象对应了getBean()方法里传入id标识符的方式。

注意@Qualifier 必须要结合 @Autowired 一起使用,不能单独使用

我们还可以使用注解 @Resource 进行注入,相当于@Autowired 和 @Qualifier 一起使用,按照名称进行注入。

@Resource(name = "userDao")//name值即需要注入对象的id标识
private UserDao userDao;

2.1.3Spring原始注解——注入普通数据类型

我们在UserServiceImpl中创建一个普通数据类型,用注解的方式获取jdbc.properties配置文件中的键值对进行赋值,

package Service;

import Dao.UserDao;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service("userService")//这里的userService对应的就是bean标签中的id
public class UserServiceImpl implements UserService {
    @Resource(name = "userDao")//name值即需要注入对象的id标识
    private UserDao userDao;

    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;

    public void save() {
        System.out.println("username:"+username+"   password:"+password);
        userDao.save();
    }
}

结果输出:

 2.1.4Spring原始注解——初始化方法和销毁方法

我们使用注解 @PostConstruct(初始化)和 @PreDestroy(销毁)实现,

@PostConstruct
public void init(){
    System.out.println("UserService初始化中.....");
}

@PreDestroy
public void destory(){
    System.out.println("UserService销毁中.....");
}

然后测试,

public void UserTest(){
    ClassPathXmlApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
    UserService service = app.getBean(UserService.class);
    service.save();
    app.close();//手动关闭容器,此时可以执行销毁方法
}

2.1.5Spring原始注解——单例多例模式

我们使用注解 @Scope 实现,用于表明这个类是单例模式还是多例模式,取值可以为singleton(单例)和prototype(多例),

@Scope("singleton")

2.2Spring新注解

使用上述的原始注解还不能全部替代xml配置文件,还需要使用注解替代的配置如下:

  • 非自定义的Bean的配置:<bean>
  • 加载properties文件的配置:<context:property-placeholder>
  • 组件扫描的配置:<context:component-scan>
  • 引入其他文件:<import>

所以出现了Spring新注解,

注解

说明

   @Configuration

用于指定当前类是一个 Spring 配置类,当创建容器时会从该类上加载注解

   @ComponentScan

用于指定 Spring 在初始化容器时要扫描的包。

作用和在 Spring xml 配置文件中的

<context:component-scan base-package="com.itheima"/>一样

   @Bean

使用在方法上,标注将该方法的返回值存储到 Spring 容器中

   @PropertySource

用于加载.properties 文件中的配置

   @Import

用于导入其他配置类

我们用这些注解实现上述不能实现的功能,首先我们新建一个Config包,用于存储Spring的配置类,新建 SpringConfiguration 类,作为Spring的核心配置类,然后新建一个DataSourceConfiguration 类,作为加载数据源的配置类,我们首先在数据源配置类中加载jdbc的配置文件,

package Config;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;

import javax.sql.DataSource;
import java.beans.PropertyVetoException;

@PropertySource("classpath:jdbc.properties")//加载jdbc的配置文件
public class DataSourceConfiguration {
    //以依赖注入的形式加载读取到容器中的jdbc属性值
    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;
}

然后我们定义一个方法,将这些jdbc的属性配置到DataSource对象中,并且将对象返回到容器中,

@Bean("dataSource")//Spring会将当前方法的返回值以指定名称加载到容器中
public DataSource getDataSource() throws PropertyVetoException {
    ComboPooledDataSource dataSource=new ComboPooledDataSource();//创建c3p0数据源对象
    dataSource.setDriverClass(driver);//设置mysql驱动
    dataSource.setJdbcUrl(url);//设置数据库路径
    dataSource.setUser(username);//设置数据库用户名
    dataSource.setPassword(password);//设置数据库密码
    return dataSource;
}

然后我们在核心配置类SpringConfiguration中导入数据源配置类,比关切设定配置组件扫描包范围,

package Config;

import org.springframework.context.annotation.*;

@Configuration//标志该类是Spring的核心配置类
@ComponentScans({@ComponentScan("Dao"),@ComponentScan("Service")})//配置组件扫描
@Import({DataSourceConfiguration.class})
public class SpringConfiguration {
}

然后我们测试代码,这时我们必须利用AnnotationConfigApplicationContext 注解对象创建容器,并读取核心配置类,以该类的字节码作为构造函数的参数进行创建,

package Test;

import Config.SpringConfiguration;
import Service.UserService;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class AnnotationTest {
    @Test
    public void UserTest(){
        AnnotationConfigApplicationContext app= new AnnotationConfigApplicationContext(SpringConfiguration.class);
        UserService service = app.getBean(UserService.class);
        service.save();
        app.close();//手动关闭容器,此时可以执行销毁方法
    }
}

三、Spring整合Junit

3.1原Junit测试Spring的问题

原始Junit测试Spring时,每个测试方法都有以下两行代码,

ClassPathXmlApplicationContext app=new ClassPathXmlApplicationContext("XXXX.xml");//获取应用上下文对象
UserService service = app.getBean(UserService.class);//获取Bean对象

这两行在每个测试类中都会出现,只有获取到了对象才能进行测试,过程比较繁琐,

所以我们希望让 SpringJunit来负责创建 Spring 容器,但是我们需要将创建容器时需要的参数(配置文件的名称,无论是xml还是注解类)告诉给SpringJunit,

然后我们直接通过注入的方式,将需要测试的Bean对象注入给测试类中,这样就可以直接测试了

3.2Spring集成Junit的步骤

Spring集成Junit的主要步骤如下:

  • 导入Spring集成Junit的坐标(和Junit的坐标不同)
  • 使用@Runwith 注解替换原来的运行期
  • 使用@ContextConfiguration 指定配置文件或配置类
  • 使用@Autowired 注入需要测试的对象
  • 创建测试方法进行测试

接下来我们进行实现,首先是导入Spring集成Junit的坐标,

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>5.0.5.RELEASE</version>
</dependency>

然后我们对UserDaoImpl和UserServiceImpl加上对应的注解,在Spring容器中生成对应的Bean对象,然后在配置文件中配置组件扫描的包,

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       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="Dao"></context:component-scan>
    <context:component-scan base-package="Service"></context:component-scan>
</beans>

然后我们创建一个测试类,利用Spring集成Junit进行测试,

package Test;

import Dao.UserDao;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)//让SpringJUnit4ClassRunner帮我们进行测试
@ContextConfiguration("classpath:applicationContext.xml")//指定配置文件的位置
public class SpringJunitTest {
    @Autowired//以自动注入的方式注入对象UserDao
    private UserDao userDao;

    @Test
    public void test(){
        userDao.save();
    }
}

结果如下:

 上面是利用xml文件进行配置,我们还可以直接用Spring的核心配置类进行配置,

@ContextConfiguration(classes = SpringConfiguration.class)//指定Spring核心配置类

结果是一样的。

猜你喜欢

转载自blog.csdn.net/weixin_39478524/article/details/121284046