2、spring程序开发步骤
2.1、spring程序开发步骤
步骤:
①导入spring开发基本包的坐标 ==》导入maven依赖
②编写Dao接口和实现类 ==》创建Bean
③创建spring核心配置文件 ==》创建applicationContext.xml
④在spring配置文件中配置UserDaoImpl ==》在配置文件中进行配置
⑤使用spring的API获得Bean实例 ==》创建ApplicationContext对象getBean
2.2、Bean标签基本配置
用于配置对象交由spring来创建。默认情况下它调用的是类中的无参构造函数,如果没有无参构造函数则不能创建成功。
2.2.1、bean的基本属性:
- id:Bean实例在容器中的唯一标识
- class:Bean的全限定名称(反射默认无参构造创建)
- scope:指对象的作用范围,取值如下:
取值范围 | 说明 |
---|---|
singleton | 默认值,单例的 |
prototype | 多例的 |
request | web项目中,spring创建一个bean对象,将对象存入到request域中 |
session | web项目中,spring创建一个bean对象,将对象存入到session域中 |
global session | web项目中,应用在portlet环境中,如果没有portlet环境那么globalsession相当于session |
当scope的取值为 singleton 时:
bean的实例化个数:1个
bean的实例化时机:当spring核心文件被加载时,bean被实例化
bean的生命周期:
- 对象创建:当应用加载,创建容器时,对象就被创建了
- 对象运行:只要容器在,对象一直活着
- 对象销毁:当应用卸载,销毁容器时,对象就被销毁了
当scope的取值为 prototype 时:
bean的实例化个数:多个
bean的实例化时机:当调用getBean()方法时,bean被实例化
bean的生命周期:
- 对象创建:当使用对象时,创建新的对象实例
- 对象运行:只要对象在使用中,对象一直活着
- 对象销毁:当长时间不使用时,会被Java垃圾回收器回收
2.2.2、bean实例化的三种方式
- 无参构造方法实例化
<bean id="user" class="com.spongebob.pojo.User"></bean>
- 工厂静态方法实例化
public class StaticFactory {
public static UserDao getUserDao(){
return new UserDaoImpl();
}
}
<bean id="user" class="com.spongebob.factory.StaticFactory" factory-method="getUserDao"></bean>
- 工厂实例方法实例化
public class DynamicFactory {
public UserDao getUserDao(){
return new UserDaoImpl();
}
}
<bean id="factory" class="com.spongebob.factory.DynamicFactory" ></bean>
<bean id="userDao" factory-bean="factory" factory-method="getUserDao"/>
2.2.3、bean的依赖注入
Dependency Injecttion 是spring框架核心IOC的具体实现。
在编写程序时,通过控制反转,把对象的创建交给了spring,但是代码中不可能出现没有依赖的情况。IOC解耦只是降低他们的依赖关系,但是不会消除。例如:业务层仍会调用持久层的方法。
那种业务层和持久层的依赖关系,在使用spring之后,就让spring来维护了。简单说,就是坐等框架把持久层对象传入业务层,而不需要我们自己去获取。
注入方式:
- 构造方法
public class UserService {
private UserDao userDao;
public UserService(UserDao userDao) {
this.userDao = userDao;
}
public UserService() {
}
public void save() {
userDao.save();
}
}
<bean id="userDao" class="com.spongebob.dao.impl.UserDaoImpl"></bean>
<bean id="userService" class="com.spongebob.service.UserService">
<constructor-arg name="userDao" ref="userDao"></constructor-arg>
</bean>
- set方法
- 、简便方式
P命名空间注入本质也是set方法注入,但比起上述的set方法注入更加方便,主要体现在配置文件中:
首先引入P命名空间:
xmlns:p="http://www.springframework.org/schema/p"
其次,需要修改注入方式:
<bean id="userService" class="com.spongebob.service.UserService" p:userDao-ref="userDao"/>
2)、常用set注入方式
<bean id="userDao" class="com.spongebob.dao.impl.UserDaoImpl"></bean>
<bean id="userService" class="com.spongebob.service.UserService">
<property name="userDao" ref="userDao"></property>
</bean>
public class UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void save() {
userDao.save();
}
}
2.2.4、bean的依赖注入的数据类型
除了对象的引用可以注入,普通数据类型、集合等都可以在容器中进行注入。
注入数据的三种数据类型
- 普通数据类型
- 引用数据类型
public class UserDaoImpl implements UserDao {
private String username;
private int age;
public void setUsername(String username) {
this.username = username;
}
public void setAge(int age) {
this.age = age;
}
@Override
public void save() {
System.out.println(username+"===="+age);
System.out.println("save running ..");
}
}
<bean id="userDao" class="com.spongebob.dao.impl.UserDaoImpl">
<property name="username" value="tuut"/>
<property name="age" value="18"/>
</bean>
- 集合数据类型
public class UserDaoImpl implements UserDao {
private List<String> strList;
private Map<String, User> userMap;
private Properties properties;
public void setStrList(List<String> strList) {
this.strList = strList;
}
public void setUserMap(Map<String, User> userMap) {
this.userMap = userMap;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
@Override
public void save() {
System.out.println("save running ..");
}
}
<bean id="userDao" class="com.spongebob.dao.impl.UserDaoImpl">
<property name="strList">
<list>
<value>aaa</value>
<value>bbb</value>
<value>ccc</value>
</list>
</property>
<property name="userMap">
<map>
<entry key="u1" value-ref="user1"></entry>
<entry key="u2" value-ref="user2"></entry>
</map>
</property>
<property name="properties">
<props>
<prop key="p1">pp1</prop>
<prop key="p2">pp2</prop>
</props>
</property>
</bean>
<bean id="user1" class="com.spongebob.pojo.User">
<property name="name" value="tutu"/>
</bean>
<bean id="user2" class="com.spongebob.pojo.User">
<property name="name" value="rebing"/>
</bean>
2.2.5、引入其他配置文件
实际开发中,spr的配置内容非常多,导致spring配置很繁杂且体积很大,所以可以将部分配置拆解到其他配置文件中,而spring主配置文件通过import标签进行加载:
<import resource="applicationContext-xxx.xml"/>
2.2.6、spring的重点配置
< bean >标签
id属性:在容器中Bean实例化的唯一标识,不允许重复
class属性:要实例化的Bean的全限定名
scope属性:Bean的作用范围,常用的是Singleton(默认)和prototype
< property >标签:属性注入
name属性:属性名称
value属性:属性值ref属性:注入的对象引用值
< list >标签
< map >标签
< properties >标签
< constructor-arg >标签:有参构造注入
< import >标签:导入其他的spring的分文件
2.3、Spring相关API
2.3.1、ApplicationContext的实现类
1)ClassPathXmlApplicationContext
它是从类的根路径下加载配置文件,推荐使用这种
2)FileSystemXmlApplicationContext
它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置
3)AnnotationConfigApplicationContext
当使用注解配置容器对象时,需要用此类来创建spring容器。它用来读取注解。
2.3.2、getBean()方法的使用
Object getBean(String var1) throws BeansException;
<T> T getBean(String var1, Class<T> var2) throws BeansException;
2.4、Spring配置数据源
数据源(连接池)的作用:
- 数据源(连接池)是提高程序性能出现的
- 事先实例化数据源,初始化部分连接资源
- 使用链接资源时从数据源中获取
- 使用完毕后将连接资源归还给数据源
常见的数据源(连接池):DBCP、C3P0、BoneCP、Druid等
2.4.1、数据源的开发步骤
①导入数据源的jar包和数据库驱动jar包
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.5</version>
</dependency>
②创建数据源对象
③设置基本的参数信息(4个基本信息)
④使用数据源获取连接资源和归还连接资源
@Test
// 测试手动创建 c3p0 数据源
public void test1() throws PropertyVetoException, SQLException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/websites");
dataSource.setUser("root");
dataSource.setPassword("admin");
Connection connection = dataSource.getConnection();
System.out.println(connection);
connection.close();
}
打印结果com.mchange.v2.c3p0.impl.NewProxyConnection@1e67b872
@Test
// 测试手动创建 druid 数据源
public void test2() throws PropertyVetoException, SQLException {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/websites");
dataSource.setUsername("root");
dataSource.setPassword("admin");
Connection connection = dataSource.getConnection();
System.out.println(connection);
connection.close();
}
打印结果com.mysql.cj.jdbc.ConnectionImpl@13c78c0b
通过编写jdbc.properties文件。
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/websites
jdbc.username=root
jdbc.password=admin
使用ResourceBundle读取配置jdbc.properties文件。
@Test
// 测试手动创建 c3p0 数据源
public void test1() throws PropertyVetoException, SQLException {
//读取配置文件
ResourceBundle rb = ResourceBundle.getBundle("jdbc");
String driver = rb.getString("jdbc.driver");
String url = rb.getString("jdbc.url");
String username = rb.getString("jdbc.username");
String password = rb.getString("jdbc.password");
//创建数据源 设置连接参数
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass(driver);
dataSource.setJdbcUrl(url);
dataSource.setUser(username);
dataSource.setPassword(password);
Connection connection = dataSource.getConnection();
System.out.println(connection);
connection.close();
}
2.4.2、使用spring配置数据源
可以将DataSource的创建权交由Spring容器去完成
-
DataSource有无参构造方法,而Spring默认就是通过无参构造方法实例化对象的
-
DataSource要想使用需要通过set方法设置数据库连接信息,而Spring可以通过set方法进行字符串注入
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"/>
<property name="user" value="root"/>
<property name="password" value="root"/>
</bean>
测试从容器中获取数据源:
ApplicationContext applicationContext = new
ClassPathXmlApplicationContext("applicationContext.xml");
DataSource dataSource = (DataSource)
applicationContext.getBean("dataSource");
Connection connection = dataSource.getConnection();
System.out.println(connection);
2.4.3、抽取jdbc配置文件
applicationContext.xml加载jdbc.properties配置文件获得连接信息。
首先,需要引入context命名空间和约束路径:
-
命名空间:xmlns:context=“http://www.springframework.org/schema/context”
-
约束路径:http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
2.5、spring注解开发
spring是轻代码而重配置的框架,配置比较繁重,影响开发效率,所以注解开发是一种趋势,注解代替xml配置文件可以简化配置,提高开发效率。
2.5.1、spring原始注解主要代替bean的配置
注解 | 说明 |
---|---|
@Component | 使用在类上,用于实例化bean |
@Controller | 使用在web层类上,用于实例化bean |
@Service | 使用在service层类上,用于实例化bean |
@Respository | 使用在dao层类上,用于实例化bean |
@Autowired | 使用在字段上,用于根据类型依赖注入 |
@Qualifier | 结合@Autowired一起使用,用于根据名称进行依赖注入 |
@Resource | 相当于@Autowired+@Qualifired,按照名称进行注入 |
@Value | 注入普通属性 |
@Scope | 标注bean的作用范围 |
@PostConstruct | 使用在方法上,标注该方法是bean的初始化方法 |
@PreDestroy | 使用在方法上,标注该方法是bean的销毁方法 |
在使用注解进行开发时,需要在applicationContext.xml中配置组件扫描,作用是指定哪个包及其子包下的bean需要进行扫描以便识别使用注解配置的类、字段和方法。
<!--注解的组件扫描-->
<context:component-scan base-package="com.spongebob"></context:component-scan>
使用上面的注解还不能全部替代xml配置文件,还需要使用注解替代的配置如下:
- 非自定义的Bean的配置:< bean>
- 加载properties文件的配置:< context:property-placeholder>
- 组件扫描的配置:< context:component-scan>
- 引入其他文件:< import>
2.5.2、spring新注解
注解 | 说明 |
---|---|
@Configuration | 用于指定当前类是一个spring配置类,当创建容器时会从该类上加载注解 |
@ComponentScan | 用于指定spring在初始化容器时要扫描的包。作用和在spring的xml配置文件中的<context:component-scan base-package=“com.spongebob”/>一样 |
@Bean | 使用在方法上,标注将该方法的返回值存储到spring容器中 |
@PropertySource | 用于加载.properties文件中的配置 |
@Import | 用于导入其他配置类 |
@Configuration
@ComponentScan("com.spongebob")
@Import({DataSourceConfiguration.class})
public class SpringConfiguration {
}
@PropertySource("classpath:jdbc.properties")
public class DataSourceConfiguration {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
}
@Bean(name="dataSource")
public DataSource getDataSource() throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass(driver);
dataSource.setJdbcUrl(url);
dataSource.setUser(username);
dataSource.setPassword(password);
return dataSource;
}
2.6、spring集成Junit
2.6.1 原始Junit测试Spring的问题
在测试类中,每个测试方法都有以下两行代码:
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
IAccountService as = ac.getBean("accountService",IAccountService.class);
这两行代码的作用是获取容器,如果不写的话,直接会提示空指针异常。所以又不能轻易删掉。
解决思路:
- 让SpringJunit负责创建Spring容器,但是需要将配置文件的名称告诉它。
- 将需要进行测试Bean直接在测试类中进行注入。
2.6.2 spring集成Junit步骤
① 导入spring集成Junit的jar包
② 使用@Runwith注解替换原来的运行期
③ 使用@ContextConfiguration指定配置文件或配置类
④ 使用@Autowired注入需要测试的对象
⑤ 创建测试方法进行测试
<!--此处需要注意的是,spring5 及以上版本要求 junit 的版本必须是 4.12 及以上--> <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
//使用@Runwith注解替换原来的运行期
@RunWith(SpringJUnit4ClassRunner.class)
public class SpringJunitTest {
}
//使用@ContextConfiguration指定配置文件或配置类
@RunWith(SpringJUnit4ClassRunner.class)
//加载spring核心配置文件
//@ContextConfiguration(value = {"classpath:applicationContext.xml"})
//加载spring核心配置类
@ContextConfiguration(classes = {SpringConfiguration.class})
public class SpringJunitTest {
}
//使用@Autowired注入需要测试的对象
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {SpringConfiguration.class})
public class SpringJunitTest {
@Autowired
private UserService userService;
}
//创建测试方法进行测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {SpringConfiguration.class})
public class SpringJunitTest {
@Autowired
private UserService userService;
@Test
public void testUserService(){
userService.save();
}
}