spring概述
1.什么是spring?
Spring是分层的 Java SE/EE应用 full-stack 轻量级开源框架,以 IoC(Inverse Of Control: 反转控制)和 AOP(Aspect Oriented Programming:面向切面编程)为内核,提供了展现层 Spring MVC 和持久层 Spring JDBC 以及业务层事务管理等众多的企业级应用技术,还能整合开源世界众多 著名的第三方框架和类库,逐渐成为使用最多的Java EE 企业应用开源框架。
2.spring体系结构
spring入门
1.引导案例-数据库查询
1.使用idea创建maven工程
打开pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.ithers</groupId>
<artifactId>day01_eesy_01jdbc</artifactId>
<version>1.0-SNAPSHOT</version>
<!--打包方式-->
<packaging>jar</packaging>
<dependencies>
<!--导入mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.26</version>
</dependency>
</dependencies>
</project>
编写JdbcDemo1
package cn.ithers.jdbc;
import java.sql.*;
/**
* 程序的耦合
*/
public class JdbcDemo1 {
public static void main(String[] args) throws Exception {
//1.注册驱动
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
//2.获取连接
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/eesy","root","202020");
//3.获取操作数据库的预处理对象
PreparedStatement pstm = conn.prepareStatement("select *from account");
//4.执行sql,得到结果
ResultSet rs = pstm.executeQuery();
//5.遍历结果
while(rs.next()){
System.out.println(rs.getString("name"));
}
//6.释放资源
rs.close();
pstm.close();
conn.close();
}
}
2.引导案例
账户的业务层和持久层的依赖关系解决。在开始 spring 的配置之前,我们要先准备 一下环境。由于我们是使用 spring 解决依赖关系,并不是真正的要做增删改查操作,所以此时我们没必要写实体 类。并且我们在此处使用的是 java 工程,不是 java web 工程。
持久层接口
package cn.ithers.dao;
/**
* @Auther: zhanghuan
* @Date: 2019/10/19 09:43
* @Description: 账户的持久层接口
*/
public interface AccountDao {
/**
*
* 模拟保存账户
*/
void saveAccount();
}
持久层实现类
package cn.ithers.dao.impl;
import cn.ithers.dao.AccountDao;
/**
* @Auther: zhanghuan
* @Date: 2019/10/19 09:43
* @Description: 账户的持久层实现类
*/
public class AccountDaoImpl implements AccountDao {
public void saveAccount() {
System.out.println("保存了账户!");
}
}
package cn.ithers.factory;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
/**
* @Auther: zhanghuan
* @Date: 2019/10/19 10:04
* @Description:
* 创建bean对象的工厂
*
* 一个创建Bean对象的工厂
*
* Bean:在计算机英语中,有可重用组件的含义。
* JavaBean:用java语言编写的可重用组件。
* javabean > 实体类
*
* 它就是创建我们的service和dao对象的。
*
* 第一个:需要一个配置文件来配置我们的service和dao
* 配置的内容:唯一标识=全限定类名(key=value)
* 第二个:通过读取配置文件中配置的内容,反射创建对象
*
* 我的配置文件可以是xml也可以是properties
*
*/
public class BeanFactory {
//定义一个Properties对象
private static Properties pros;
//定义一个Map,用于存放我们创建的对象,把它称之为容器。
private static Map<String,Object> beans;
//使用静态代码块为Properties赋值
static {
try {
//实例化对象
pros = new Properties();
//获取Properties文件的流对象
InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
pros.load(in);
//实例化容器
beans = new HashMap<>();
//取出配置文件所有的key
Enumeration keys = pros.keys();
//遍历枚举
while (keys.hasMoreElements()) {
//取出每一个key
String key = keys.nextElement().toString();
//根据key获取value
String beanPath = pros.getProperty(key);
//反射创建对象
Object value = Class.forName(beanPath).newInstance();
beans.put(key,value);
}
} catch (Exception e) {
throw new ExceptionInInitializerError("初始化Properties失败!");
}
}
public static Object getBean(String beanName) {
return beans.get(beanName);
}
/*public static Object getBean(String beanName) {
Object bean = null;
try {
String beanPath = pros.getProperty(beanName);
bean = Class.forName(beanPath).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return bean;
}*/
}
业务层接口
package cn.ithers.service;
/**
* 账户业务层的接口
*/
public interface AccountService {
/**
* 模拟保存账户
*/
void saveAccount();
}
业务层实现类
package cn.ithers.service.impl;
import cn.ithers.dao.AccountDao;
import cn.ithers.factory.BeanFactory;
import cn.ithers.service.AccountService;
/**
* 账户的业务层实现类
*/
public class AccountServiceImpl implements AccountService {
// public AccountDao accountDao = new AccountDaoImpl();
public AccountDao accountDao = (AccountDao) BeanFactory.getBean("accountDao");
public void saveAccount(){
accountDao.saveAccount();
}
}
表现层调用业务测
package cn.ithers.ui;
import cn.ithers.factory.BeanFactory;
import cn.ithers.service.AccountService;
/**
* @Auther: zhanghuan
* @Date: 2019/10/19 09:50
* @Description: 模拟表现层用于调用业务层
*/
public class Client {
public static void main(String[] args) {
// AccountService accountService = new AccountServiceImpl();
AccountService accountService = (AccountService) BeanFactory.getBean("accountService");
accountService.saveAccount();
}
}
使用spring
sping注解
获取spring的Ioc核心容器,并根据id获取对象
-
ApplicationContext的三个常用实现类:
-
ClassPathXmlApplicationContext:它可以加载类路径下的配置文件,要求配置文件必须在类路径下。不在的话,加载不了。(更常用)
-
FileSystemXmlApplicationContext:它可以加载磁盘任意路径下的配置文件(必须有访问权限)
-
AnnotationConfigApplicationContext:它是用于读取注解创建容器的,是明天的内容。
核心容器的两个接口引发出的问题: -
ApplicationContext: 单例对象适用 采用此接口
它在构建核心容器时,创建对象采取的策略是采用立即加载的方式。也就是说,只要一读取完配置文件马上就创建配置文件中配置的对象。 -
BeanFactory: 多例对象使用
它在构建核心容器时,创建对象采取的策略是采用延迟加载的方式。也就是说,什么时候根据id获取对象了,什么时候才真正的创建对象。
在pom.xml中导入
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.ithers</groupId>
<artifactId>day02-eesy_04account_annoioc_withoutxml</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.4</version>
</dependency>
<!--导入mysql坐标-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<!--导入数据库连接池坐标-->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
</dependency>
</dependencies>
</project>
package cn.zh.ui;
import cn.zh.service.AccountService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @Auther: zhanghuan
* @Date: 2019/10/19 09:50
* @Description: 模拟表现层用于调用业务层
*/
public class Client {
public static void main(String[] args) {
//1.获取核心容器对象
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
// ApplicationContext applicationContext = new FileSystemXmlApplicationContext("");
//2.根据id获取对象
// AccountService accountService = (AccountService) applicationContext.getBean("accountService");
AccountService accountService = applicationContext.getBean("accountService",AccountService.class);
accountService.saveAccount();
}
}
/**
*
*
* 曾经XML的配置:
* <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"
* scope="" init-method="" destroy-method="">
* <property name="" value="" | ref=""></property>
* </bean>
*
* 用于创建对象的
* 他们的作用就和在XML配置文件中编写一个<bean>标签实现的功能是一样的
* Component:
* 作用:用于把当前类对象存入spring容器中(就是把被此标注的类反射创建一个对象并且保存到spring容器中)
* 属性:
* value:用于指定bean的id。当我们不写时,它的默认值是当前类名,且首字母改小写。
* Controller:一般用在表现层
* Service:一般用在业务层
* Repository:一般用在持久层
* 以上三个注解他们的作用和属性与Component是一模一样。
* 他们三个是spring框架为我们提供明确的三层使用的注解,使我们的三层对象更加清晰
*
*
* 用于注入数据的
* 他们的作用就和在xml配置文件中的bean标签中写一个<property>标签的作用是一样的
* Autowired:
* 作用:自动按照类型注入。只要容器中有唯一的一个bean对象类型和要注入的变量类型匹配,就可以注入成功
* 如果ioc容器中没有任何bean的类型和要注入的变量类型匹配,则报错。
* 如果Ioc容器中有多个类型匹配时:
* 出现位置:
* 可以是变量上,也可以是方法上
* 细节:
* 在使用注解注入时,set方法就不是必须的了。
* Qualifier:
* 作用:在按照类中注入的基础之上再按照名称注入。它在给类成员注入时不能单独使用。但是在给方法参数注入时可以(稍后我们讲)
* 属性:
* value:用于指定注入bean的id。
* Resource
* 作用:直接按照bean的id注入。它可以独立使用
* 属性:
* name:用于指定bean的id。
* 以上三个注入都只能注入其他bean类型的数据,而基本类型和String类型无法使用上述注解实现。
* 另外,集合类型的注入只能通过XML来实现。
*
* Value
* 作用:用于注入基本类型和String类型的数据
* 属性:
* value:用于指定数据的值。它可以使用spring中SpEL(也就是spring的el表达式)
* SpEL的写法:${表达式}
*
* 用于改变作用范围的
* 他们的作用就和在bean标签中使用scope属性实现的功能是一样的
* Scope
* 作用:用于指定bean的作用范围
* 属性:
* value:指定范围的取值。常用取值:singleton prototype
*
* 和生命周期相关 了解
* 他们的作用就和在bean标签中使用init-method和destroy-methode的作用是一样的
* PreDestroy
* 作用:用于指定销毁方法
* PostConstruct
* 作用:用于指定初始化方法
*/
* spring中的新注解
* Configuration
* 作用:指定当前类是一个配置类
* 细节:当配置类作为AnnotationConfigApplicationContext对象创建的参数时,该注解可以不写。
* ComponentScan
* 作用:用于通过注解指定spring在创建容器时要扫描的包
* 属性:
* value:它和basePackages的作用是一样的,都是用于指定创建容器时要扫描的包。
* 我们使用此注解就等同于在xml中配置了:
* <context:component-scan base-package="com.itheima"></context:component-scan>
* Bean
* 作用:用于把当前方法的返回值作为bean对象存入spring的ioc容器中
* 属性:
* name:用于指定bean的id。当不写时,默认值是当前方法的名称
* 细节:
* 当我们使用注解配置方法时,如果方法有参数,spring框架会去容器中查找有没有可用的bean对象。
* 查找的方式和Autowired注解的作用是一样的
* Import
* 作用:用于导入其他的配置类
* 属性:
* value:用于指定其他配置类的字节码。
* 当我们使用Import的注解之后,有Import注解的类就父配置类,而导入的都是子配置类
* PropertySource
* 作用:用于指定properties文件的位置
* 属性:
* value:指定文件的名称和路径。
* 关键字:classpath,表示类路径下
*/
主配置文件
jdbcConfig.properties文件
JdbcConfige配置文件
package cn.ithers.config;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.commons.dbutils.QueryRunner;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import javax.sql.DataSource;
import java.beans.PropertyVetoException;
/**
* @Auther: zhanghuan
* @Date: 2019/10/21 10:32
* @Description: 和spring连接数据库相关的类
*/
public class JdbcConfig {
@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 = "runner")
@Scope("prototype")
public QueryRunner createQueryRunner(DataSource dataSource) {
return new QueryRunner(dataSource);
}
//创建数据源对象
@Bean(name="dataSource")
public DataSource createDataSource() {
try {
ComboPooledDataSource ds = new ComboPooledDataSource();
ds.setDriverClass(driver);
ds.setJdbcUrl(url);
ds.setUser(username);
ds.setPassword(password);
return ds;
} catch (PropertyVetoException e) {
throw new RuntimeException(e);
}
}
}
spring整合junit
* 使用Junit单元测试:测试我们的配置
* Spring整合junit的配置
* 1、导入spring整合junit的jar(坐标)
* 2、使用Junit提供的一个注解把原有的main方法替换了,替换成spring提供的
* @Runwith
* 3、告知spring的运行器,spring和ioc创建是基于xml还是注解的,并且说明位置
* @ContextConfiguration
* locations:指定xml文件的位置,加上classpath关键字,表示在类路径下
* classes:指定注解类所在地位置
*
* 当我们使用spring 5.x版本的时候,要求junit的jar必须是4.12及以上
*/
导入依赖