一、spring概述
1.1 框架概述
框架是一个封装了很多功能和模块的程序的半成品。
可以理解为是一个由很多工具类组合而成的一个工具包。
框架可以提高我们的开发效率
1.2 Spring是什么
Spring是分层的 Java SE/EE应用 full-stack 轻量级开源框架。是Java开发的灵魂框架。
Spring有两大内核:
IOC(Inverse Of Control:控制反转)
AOP(Aspect Oriented Programming:面向切面编程)
1.3 Spring功能
IOC:控制反转,其实就是把对象的创建权,交给spring,由Spring负责给我们创建对象
DI: 依赖注入,其实就是给对象的成员变量赋值。
AOP:面向切面编程,底层就是动态代理
事务: Spring提供了声明式事务,也就是说,我们可以通过配置的方式来添加事务。
二、 入门案例
2.1 Spring程序开发步骤
①导入 Spring 开发的基本包坐标(5.1.9.release)
②创建Spring核心配置文件
③在 Spring 配置文件中配置要创建的对象
④通过spring获取资源(获取创建的对象)
2.2 案例实现
① 导入坐标
<!--spring核心-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
② 创建Spring核心配置文件,③配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 1.创建spring控制的资源(让spring帮忙创建该类的对象)-->
<bean id="userService" class="com.itheima.service.impl.UserServiceImpl"/>
</beans>
④ 通过spring获取资源(获取创建的对象)
public class UserApp {
public static void main(String[] args) {
//1.加载配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//2.获取资源
UserService userService = (UserService) ctx.getBean("userService");
//3.调用方法
userService.save();
}
}
三、IOC配置-XML格式
3.1 Bean标签基本配置
作用:定义spring中的资源,受此标签定义的资源将受到spring控制
格式:
<beans>
<bean 属性名="属性值" ></bean>
</beans>
3.2 常见属性
id:Bean实例在Spring容器中的唯一标识,通过id值获取bean
class:Bean的类型, spring创建的就是该类的对象
name:Bean的名称,可以通过name值获取bean,用于多人配合时给bean起别名
ps:其他属性
3.3.1 scope
格式:
<bean scope="singleton"></bean>
取值:
- singleton:设定创建出的对象保存在spring容器中,是一个单例的对象,
- prototype:设定创建出的对象保存在spring容器中,是一个多例的对象
3.4 对象创建方式
1) 使用无参构造方法实例化
默认调用无参构造方法创建对象,如果bean中没有默认无参构造函数,将会创建失败
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
2) 工厂静态方法实例化
工厂静态方法实例化, 指的是在创建对象的时候,是通过调用某个类的静态方法才能创建对象.
例如:LocalDate now = LocalDate.now();
<!-- LocalDate now = LocalDate.now(); -->
<bean id="now" class="java.time.LocalDate" factory-method="now"/>
3) 工厂实例方法实例化
工厂实例方法实例化, 指的是在创建对象的时候, 需要通过其他类的对象才能创建对象.
<!-- LocalDate now = LocalDate.now(); -->
<bean id="now" class="java.time.LocalDate" factory-method="now"/>
<!-- DayOfWeek dayOfWeek = now.getDayOfWeek(); -->
<bean id="dayOfWeek" factory-bean="now" factory-method="getDayOfWeek"/>
四、 依赖注入-DI
4.1 概述
依赖注入(Dependency Injection):是SpringIOC的具体体现,简单来说,就是给对象的属性赋值
4.2 Bean的依赖注入方式
4.2.1 Set方法赋值(常用)
①在UserServiceImpl中添加setUserDao方法
public class UserServiceImpl implements UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void save() {
userDao.save();
}
}
②配置Spring容器调用set方法进行注入
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
<bean id="userService" class="com.itheima.service.impl.UserServiceImpl">
<!-- 使用setUserDao方法,把userDao对象,注入userService中 -->
<property name="userDao" ref="userDao"/>
</bean>
4.2.2 构造方法赋值
①在类中提供有参构造
public class UserServiceImpl implements UserService {
private UserDao userDao;
public UserServiceImpl(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void save() {
userDao.save();
}
}
②配置Spring容器调用有参构造时进行注入
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
<bean id="userService" class="com.itheima.service.impl.UserServiceImpl">
<!-- 使用构造方法,把userDao对象,注入userService中 -->
<constructor-arg name="userDao" ref="userDao"></constructor-arg>
</bean>
4.3 集合类型数据注入
- list
<property name="al">
<list>
<value>itheima</value>
<value>66666</value>
<!--如果集合元素是对象,则可以注入对象(直接创建新对象)-->
<bean class="com.itheima.domain.User"/>
<!--如果集合元素是对象,则可以注入对象(引入已经创建的对象)-->
<ref bean="u1"/>
</list>
</property>
- rops
<property name="properties">
<props>
<prop key="name">itheima666</prop>
<prop key="value">666666</prop>
</props>
</property>
- array
<property name="arr">
<array>
<value>123456</value>
<value>66666</value>
</array>
</property>
- set
<property name="hs">
<set>
<value>itheima</value>
<value>66666</value>
</set>
</property>
- map
<property name="hm">
<map>
<entry key="name" value="itheima66666"/>
<entry key="value" value="6666666666"/>
</map>
</property>
五、 其他
5.1 引入properties文件
语法:
<context:property-placeholder location="classpath:filename.properties">
获取数据:
<property name="propertyName" value="${propertiesName}"/>
- 注意:如果需要加载所有的properties文件,可以使用*.properties表示加载所有的properties文件
- 注意:读取数据使用${propertiesName}格式进行,其中propertiesName指properties文件中的属性名
5.2 引入其他配置文件
如果当前项目有多个配置文件, 则可以:
1.在主配置文件中引入其他配置文件
2.在加载时,直接加载多个配置文件
引入其他配置文件
<import resource="被引入配置文件的路径"/>
直接加载多个配置文件
new ClassPathXmlApplicationContext("config1.xml","config2.xml");
注意:
- 同id的bean,后定义的覆盖先定义的
- 导入配置文件可以理解为将导入的配置文件复制粘贴到对应位置
- 导入配置文件的顺序与位置不同可能会导致最终程序运行结果不同
5.3 ApplicationContext对象的获取
//加载配置文件,获取Spring核心容器
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
//加载配置文件,获取Spring核心容器, 一般不用
ApplicationContext ac2 = new FileSystemXmlApplicationContext("配置文件绝对路径");
//加载配置类, 获取Spring核心容器, 用于注解开发
ApplicationContext ac3 = new AnnotationConfigApplicationContext(配置类.class);
5.4 实例对象的获取
//加载配置文件,获取Spring核心容器
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
//获取Spring核心容器中,id叫做"userService"的对象
UserService userService = (UserService)ac.getBean("userService");
//获取Spring核心容器中,类型是"UserService"的对象
UserService userService = ac.getBean(UserService.class);
//获取Spring核心容器中,,id叫做"userService"的,类型是"UserService"的对象
UserService userService = ac.getBean("userService",UserService.class);
扩展知识块
一、注解开发
1.1 意义
Spring是轻代码而重配置的框架,配置比较繁重,影响开发效率,所以注解开发是一种趋势,注解代替xml配置文件可以简化配置,提高开发效率。
1.2 启动注解功能
位置: 在spring的配置文件中进行开启
语法: <context:component-scan base-package="包名"/>
说明:
- 在进行包所扫描时,会对配置的包及其子包中所有文件进行扫描
- 扫描过程是以文件夹递归迭代的形式进行的
- 扫描过程仅读取合法的java文件
- 扫描时仅读取spring可识别的注解
- 扫描结束后会将可识别的有效注解转化为spring对应的资源加入IoC容器
注意:
- 无论是注解格式还是XML配置格式,最终都是将资源加载到IoC容器中,差别仅仅是数据读取方式不同
- 从加载效率上来说注解优于XML配置文件
.3 常用注解
1.3.1 创建对象的注解
@Component:使用在类上,用于实例化Bean
@Controller:使用在web层类上,用于实例化Bean
@Service:使用在service层类上,用于实例化Bean
@Repository:使用在dao层类上用于,实例化Bean
案例:
@Repository("userDao")
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("save running... ...");
}
}
//上述四个注解作用一样,也就是说,这里同样可以写其他三个注解,但约定俗成,Dao层一般使用Repository
1.3.2 作用范围的注解
@Scope
两个取值:“prototype” -> 多例的,“singleton” -> 单例的(默认)
案例:
@Scope("singleton")
public class UserDaoImpl implements UserDao {
//此处省略代码
}
1.3.3 初始化注解(了解)
@PostConstruct
被标注的方法,在对象被创建的时候执行
@PreDestroy
被标注的方法,在对象被销毁的时候执行
案例:
@PostConstruct
public void init(){
System.out.println("初始化方法....在对象被创建的时候执行....");
}
@PreDestroy
public void destroy(){
System.out.println("销毁方法....在对象被销毁的时候执行....");
}
1.3.4 第三方对象注解-@Bean
作用:
使用在方法上,Spring会自动执行该方法,并把方法返回的对象,存储在spring容器中
范例:
@Bean("dataSource")
public DataSource getDataSource() throws PropertyVetoException {
ComboPooledDataSource ds = new ComboPooledDataSource();
ds.setDriverClass(driver);
ds.setJdbcUrl(url);
ds.setUser(username);
ds.setPassword(password);
return ds;
}
说明:
- 因为第三方bean无法在其源码上进行修改,使用@Bean解决第三方bean的引入问题
- 该注解用于替代XML配置中的静态工厂与实例工厂创建bean,不区分方法是否为静态或非静态
- @Bean所在的类必须被spring扫描加载,否则该注解无法生效
相关属性:
- value(默认):定义bean的访问id
1.3.5 依赖注入的注解
@Autowired
根据类型依赖注入,如果找到多个,则根据变量名依赖注入
@Qualifier
与@Autowired一起使用,用于根据名称进行依赖注入
@Value
注入普通属性。一般用于获取properties中的key,然后注入成员变量中
案例:使用@Autowired对引用类型进行注入
@Service("userService")
public class UserServiceImpl implements UserService {
@Autowired //根据类型依赖注入,如果找到多个,则根据变量名userDao依赖注入
private UserDao userDao;
@Override
public void save() {
userDao.save();
}
}
使用@Value进行字符串的注入
@Repository("userDao")
public class UserDaoImpl implements UserDao {
@Value("注入普通数据") //注入普通数据
private String str;
@Value("${jdbc.driver}") //获取已经加载到容器中的properties中的指定的键,并注入
private String driver;
@Override
public void save() {
System.out.println(str);
System.out.println(driver);
}
}
1.4 其他注解
1.4.1 @Primary
作用:
定义在类上, 当@Autowired按类型装配时, 默认先装配该类对象. 提高该类优先级
范例:
@Primary
public class ClassName{}
说明:多个@Primary会导致优先级设置无效
1.4.2 @Inject与@Named
@Inject与@Named是JSR330规范中的注解,功能与@Autowired和@Qualifier完全相同,适用于不同架构场景
1.4.3 @Resource
说明:
- @Resource是JSR250规范中的注解,可以简化书写格式
- @Resource相当于"@Autowired + @Qualifier"
属性:
- name:设置注入的bean的id
- type:设置注入的bean的类型,接收的参数为Class类型
二、纯注解开发
2.1 概述
Spring所谓的纯注解开发,其实就是完全摒弃Spring的配置文件, 使用注解完全替代其对应功能。
2.2 对应注解
@Configuration
用于指定当前类是一个 Spring配置类,当创建容器时会从该类上加载注解
@ComponentScan
用于指定 Spring 在初始化容器时要扫描的包。
@PropertySource
用于加载.properties 文件中的配置
@Import
用于导入其他配置类
2.2 新注解详解
2.2.1 @Configuration
用于指定 Spring 在初始化容器时要扫描的包。
相当于xml配置时的<context:component-scan base-package=“com.itheima”/>
@Configuration
@ComponentScan("com.itheima")
public class SpringConfiguration {
}
2.2.3 @Import
用于导入其他的配置类
相当于xml配置时的
@Configuration
@ComponentScan("com.itheima")
@Import({DataSourceConfiguration.class})
public class SpringConfiguration {
}
2.2.4 @PropertySource
用于properties配置文件
相当于xml配置时的<context:property-placeholder location=“classpath:jdbc.properties”/>
@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;
}
2.2.5 加载配置类
@Test
public void testAnnoConfiguration() throws Exception {
//根据配置类SpringConfiguration.class,获取Spring的核心容器
ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class);
//获取userService对象
UserService userService = (UserService)ac.getBean("userService");
userService.save();
//获取dataSource对象
DataSource dataSource = (DataSource)ac.getBean("dataSource");
Connection connection = dataSource.getConnection();
System.out.println(connection);
}
三、Bean加载控制
3.1 @DependsOn
作用:
定义在类或者方法上, 用来控制bean的加载顺序,使其在指定bean加载完毕后再加载
范例:@DependsOn("beanId") public class ClassName { }
说明:
- 配置在方法上,使@DependsOn指定的bean优先于@Bean配置的bean进行加载
- 配置在类上,使@DependsOn指定的bean优先于当前类中所有@Bean配置的bean进行加载
- 配置在类上,使@DependsOn指定的bean优先于@Component等配置的bean进行加载
场景:
- 微信订阅号,发布消息和订阅消息的bean的加载顺序控制
- 双11活动期间,零点前是结算策略A,零点后是结算策略B,策略B操作的数据为促销数据。策略B加载顺序与促销数据的加载顺序
3.2 Order
作用:
定义在类上, 用来控制配置类的加载顺序, 让配置类按照指定的序号进行加载
范例:@Order(1) public class SpringConfigClassName { }
场景:
多个种类的配置出现后,优先加载系统级的,然后加载业务级的,避免细粒度的加载控制
3.3 @Lazy
作用:
定义在类或方法上, 控制bean的加载时机,使其延迟加载
范例:@Lazy public class ClassName { }
场景:
程序灾难出现后对应的应急预案处理是启动容器时加载时机
四、Spring整合Junit
4.1 概述
在原来的代码中,在测试类中,不能正常使用依赖注入。
如果想让测试类中,也可以使用依赖注入,则需要Spring整合Junit
4.2 Spring集成Junit步骤
①导入spring集成Junit的坐标
②使用@Runwith注解替换原来的运行期
③使用@ContextConfiguration指定配置文件或配置类
④使用@Autowired注入需要测试的对象
⑤创建测试方法进行测试
4.3 Spring集成Junit代码实现
①导入spring集成Junit的坐标
<!--此处需要注意的是,spring5 及以上版本要求 junit 的版本必须是 4.12 及以上-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
②使用@Runwith表示,当前测试类被spring接管
@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();
}
}
五、 Spring组件扫描
5.1 XML配置(只扫描service)
方式1:
<context:component-scan base-package="com.itheima.service"/>
方式2:
<context:component-scan base-package="com.itheima">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
方式3
<context:component-scan base-package="com.itheima" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
</context:component-scan>
5.2 注解配置(只扫描service)
方式1
@ComponentScan("com.itheima.service")
方式2
@ComponentScan(value = "com.itheima",excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = Controller.class)
})
方式3
@ComponentScan(value = "com.itheima",includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = Service.class)
},useDefaultFilters = false)