目录
Spring设计理念
Spring是面向Bean的编程
一、Spring的两大核心机制
1、IOC/ DI:控制反转和依赖注入
控制反转:将对象的创建由代码本身转移到外部容器———解耦
配置文件中配置bean
依赖注入:在使用时,从外部容器获取需要的对象
在bean中注入属性值/普通数据/对象、构造方法的参数值/普通数据/对象
2、AOP:面向切面编程
将散布在程序中的公共功能集中处理
在不改变原有逻辑/功能的前提下对系统/功能做增强处理(前置、后置、异常、最终、
环绕)
Spring的优点
1、低侵入式设计
2、独立于各种应用服务器
3、依赖注入特性将组件关系透明化,降低了耦合度
4、面向切面编程特性允许将通用任务进行集中式处理
5、与第三方框架的良好整合
二、IOC/ DI:控制反转 / 依赖注入:
将组件对象的控制权从代码本身转移到外部容器组件化的思想:分离关注点,使用接口,不再关注
实现
依赖的注入:将组件的构建和使用分开
目的:解耦合,实现每个组件时只关注组件内部的事情
首先要加Spring的依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
创建applicationContext.xml文件
在applicationContext.xml文件中编写bean
1、bean的基础配置:
类型:标签
所属:beans标签
功能:定义Spring核心容器管理对象
格式:
<beans>
<bean/>
<bean></bean>
</beans>
属性列表:
id | bean的id,使用容器可以通过id值获取对应的bean,在一个容器中id值唯一 |
class | bean的类型,即配置的bean的全路径类名 |
示例:
<bean id="bookDao" class="com.demo.dao.impl.BookDaoImpl" />
<bean id="bookService" class="com.demo.service.impl.BookServiceImpl"></bean>
bean别名配置
实用name属性,所属bean标签
功能:定义bean的别名,可定义多个,用逗号(,)或分号(;)或空格分隔
示例:
<bean id="bookDao" name="dao bookDaoImpl" class="com.demo.dao.imp1.BookDaoImpl" />
<bean name="service, bookServiceImpl" class="com.demo.service.impl.BookServiceImpl" />
注意:
获取bean无论是通过id还是name获取,如果无法获取到,将抛出异常NoSuchBeanDefinitionExceptionNoSuchBeanDefinitionException: No bean named 'bookServiceImpl' available
bean的作用范围
scope:所属bean标签
功能:singleton:单例 prototype:非单例
示例:
<bean id="bookDao" class="com.demo.dao.impl.BookDaoImpl" scope="prototype"/>
2、bean的实例化
bean本质上就是对象,创建bean使用构造方法完成
bean实例化的四种方式
1、使用构造方法(默认无参方法)常用
提供可访问的构造方法
public class BookDaoImpl implements BookDao {
public void save() {
system.out.println( "book dao save ..." );
}
}
配置bean
<bean id="bookDao" class="com.demo.dao.impl.BookDaoImpl“/>
注意:无参构造方法如果不存在,将抛出异常BeanCreationException
2、使用静态工厂(了解)
public class OrderDaoFactory {
public static orderDao getorderDao(){
return new OrderDaoImpl();
}
}
配置bean
<bean id="orderDao" factory-method="getorderDao"
class="com.itheima.factory.orderDaoFactory"/>
3、使用实例工厂(了解)
public class UserDaoFactory {
public UserDao getUserDao(){
return new UserDao1mpl();
}
}
配置bean
<bean id="userDaoFactory" class="com.demo.factory.UserDaoFactory" />
<!--userDaoFactory 上面的和下面的是一个-->
<bean id="userDao"
factory-method="getUserDao"factory-bean="userDaoFactory"/>
4、使用FactoryBean
public class UserDaoFactoryBean implements FactoryBean<UserDao>{
public UserDao getobject() throws Exception {
return new UserDaoImpl();
}
public class<?> getObjectType() {
return UserDao.class;
}
}
3、配置bean
<bean id="userDao" class="com.demo.factory.UserDaoFactoryBean"/>
bean的生命周期:bean从创建到销毁的整体过程
初始化容器
1.创建对象(内存分配)
2.执行构造方法
3.执行属性注入( set操作)
4.执行bean初始化方法
使用bean:执行业务操
关闭/销毁容器:执行bean销毁方法
bean生命周期控制:在bean创建后到销毁前做一些事情
提供生命周期空值方法
public class BookDaoImpl implements BookDao {
public void save( ) {
system.out.println("book dao save ..." );
}
public void init(){
system.out.print1n( "book init ..." );
}
public void destory(){
system.out.println( "book destory ..." );
}
}
配置生命周期控制方法
<bean id="bookDao" class="com.demo.dao.impl.BookDaoImpl" init-method="init" destroy-method="destory "/>
bean销毁时机
容器关闭前触发bean的销毁
关闭容器方式∶
1、手工关闭容器:configurableApplicationContext接口close()操作
2、注册关闭钩子,在虚拟机退出前先关闭容器再退出虚拟机:ConfigurableApplicationContext接口registerShutdownHook()操作
public class AppForLifecycle {
public static void main( string[] args ) {
ClassPathXmlApplicationContext ctx = new classPathXmlApplicationContext(
"applicationContext.xml");
ctx.close();
}
}
4、依赖注入方式
setter注入:简单类型 引用类型
构造器注入:简单类型 引用类型
setter注入-简单类型
在bean中定义引用类型属性并提供可访问的set方法
public class BookDaoImpl implements BookDao {
private int connectionNumber;
public void setConnectionNumber(int connectionNumber) {
this.connectionNumber = connectionNumber;
}
}
配置中使用property标签value属性注入简单类型数据
<bean id="bookDao" class="com.demo.dao.impl.BookDaoImpl">
<property name="connectionNumber" value="10" />
</bean>
setter注入-引用类型
在bean中定义引用类型属性并提供可访问的set方法
public class BookServiceImpl implements BookService{
private BookDao bookDao;
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
}
配置中使用property标签ref属性注入引用类型对象
<bean id="bookService" class="com.demo.service.impl.BookServiceImpl">
<property name="bookDao" ref="bookDao" / >
</bean>
<bean id="bookDao" class="com.demo.dao.impl.BookDaoImpl" />
构造器注入-引用类型(了解)
在bean中定义引用类型属性并提供可访问的构造方法
public class BookServiceImpl implements BookService{
private BookDao bookDao;
public BookServiceImpl(BookDao bookDao) {
this.bookDao = bookDao;
}
}
配置中使用constructor-arg标签ref属性注入引用类型对象
<bean id="bookService" class="com.demo.service.impl.BookServiceImpl">
<constructor-arg name="bookDao" ref="bookDao" />
</bean>
<bean id="bookDao" class="com.demo.dao.imp1.BookDaoImpl" />
构造器注入-简单类型(了解)
在bean中定义引用类型属性并提供可访问的set方法
public class BookDaoImpl implements BookDao {
private int connectionNumber;
public void setConnectionNumber(int connectionNumber) {
this.connectionNumber = connectionNumber;
}
配置中使用constructor-arg标签value属性注入简单类型数据
<bean id="bookDao" class="com.demo.dao.impl.BookDaoImpl">
<constructor-arg name="connectionNumber" value="10"/>
</bean>
依赖注入方式选择
1、强制依赖使用构造器进行,使用setter注入有概率不进行注入导致null对象出现
2、可选依赖使用setter注入进行,灵活性强
3、 Spring框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相对严谨
4、如果有必要可以两者同时使用,使用构造器注入完成强制依赖的注入,使用setter注入完成可选
依赖的注入
5、实际开发过程中还要根据实际情况分析,如果受控对象没有提供setter方法就必须使用构造器注入
6、自己开发的模块推荐使用setter注入
依赖自动装配
IOC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称为自动装配·
自动装配方式:1、按类型(常用)2、按名称3、按构造方法4,不启用自动装配
配置中使用bean标签autowire属性设置自动装配的类型
<bean id="bookDao" class="com.demo.dao.impl.BookDaoImpl" />
<bean id="bookService" class=" com.demo.service.impl.BookServiceImpl" autowire="byType" />
依赖自动装配特征
自动装配用于引用类型依赖注入,不能对简单类型进行操作
使用按类型装配时( byType ) 必须保障容器中相同类型的bean唯一,推荐使用
使用按名称装配时 ( byName )必须保障容器中具有指定名称的bean,因变量名与配置耦合,不推
荐使用
自动装配优先级低于setter注入与构造器注入,同时出现时自动装配配置失效
注入集合对象
注入list对象
<property name="list">
<list>
<value>itcast</value>
<value>demo</value>
</list>
</property>
注入set对象
<property name="set">
<set>
value>itcast</value>
<value>demo</value>
< /set>
</ property>
注入map对象
<property name="map" >
<map>
<entry key=" country" value="china" />
<entry key="province" value="henan" />
<entry key="city" value="kaifeng" />
</map>
</property>
注入Properties
<property name="properties">
<props>
<prop key="country">china</ prop>
<prop key="province" >henan</ prop>
<prop key="city">kaifeng</prop>
</props>
</property>
数据源对象管理
导入druid坐标
<dependency>
<groupId>com.alibaba</ groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
配置数据源对象作为spring管理的bean
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://127.0.0.1:3306/spring_db" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
加载properties文件
开启context命名空间
使用context命名空间,加载指定properties文件
<context:property-placeholder location="jdbc.properties"/>
使用${ }读取加载的属性值
<property name="username" value="${jdbc.username}"/>
不加载系统属性
<context:property-placeholder location="jdbc.properties" system-properties-mode="NEVER"/>
加载多个properties文件
<context:property-placeholder location="jdbc.properties,msg.properties"/>
加载所有properties文件
<context:property-placeholder location="*.properties"/>
加载properties文件标准格式
<context:property-placeholder location="classpath:*.properties" />
从路径或jar包中搜索并加载properties文件
<context:property-placeholder location="classpath*:*.properties" />
创建容器
方式一:类路径加载配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xm1");
方式二:文件路径加载配置文件
ApplicationContext ctx = new FileSystemxmlApplicationContext("D:\\applicationContext.xml" );
方式三:加载多个配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("bean1.xm1","bean2.xml" );
获取bean
方式一:使用bean名称获取
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
方式二:使用bean名称获取并指定类型
BookDao bookDao = ctx.getBean("bookDao",BookDao.class);
方式三:使用bean类型获取
BookDao bookDao = ctx.getBean(BookDao.class);
BeanFactory初始化
类路径加载配置文件
Resource resources = new ClassPathResource("applicationContext.xml");
BeanFactory bf = new Xm1BeanFactory(resources);
BookDao bookDao = bf.getBean("bookDao",BookDao.class);
bookDao.save();
BeanFactory创建完毕后,所有的bean均为延迟加载
bean的属性
依赖注入属性
三、注解开发定义bean
使用@Component定义bean
@Component("bookDao")
public class BookDaoImpl implements BookDao {
}
@Component
public class BookServiceImpl implements BookService {
}
核心配置文件中通过组件扫描加载bean
<context:component-scan base-package="com.demo"/>
Spring提供@Component注解的三个衍生注解
@Controller:用于表现层bean定义
@service :用于业务层bean定义
@Repository :用于数据层bean定义
@Repository( "bookDao")
public class BookDaoImpl implements BookDao {
}
@Service
public class BookServiceImpl implements BookService {
}
1、纯注解开发
Spring3.0开启了纯注解开发模式,使用Java类替代配置文件,开启了Spring快速开发赛道
Java类代替Spring核心配置文件,
@Configuration注解用于设定当前类为配置类
@ComponentScan注解用于设定扫描路径,此注解只能添加一次,多个数据请用数组格式
@ComponentScan({com.demo.service" , "com.demo.dao"})
读取Spring核心配置文件初始化容器对象切换为读取Java配置类初始化容器对象
//加载配置文件初始化容器
ApplicationContext ctx = new classPathXmlApplicationContext( "applicationContext.xml" );
//加载配置类初始化容器
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
注解定义bean的作用范围
使用@Scope定义bean作用范围
@Repository
@scope("singleton")
public class BookDaoImpl implements BookDao {
}
注解定义bean生命周期
使用@PostConstruct、@PreDestroy定义bean生命周期
@Repository
@scope("singleton")
public class BookDaoImpl implements BookDao {
public BookDaoImpl() {
system.out.println( "book dao constructor ..." );
}
@PostConstruct
public void init(){
system.out.println( " book init ..." );
}
@PreDestroy
public void destroy(){
system.out.println( "book destory ..." );
}
}
注解依赖注入
使用@Autowired注解开启自动装配模式(按类型)
@Service
public class BookServiceImpl implements BookService {
@Autowired
private BookDao bookDao;
public void save() {
system.out.println("book service save ..." );
bookDao.save();
}
}
注意:
1、自动装配基于反射设计创建对象并暴力反射对应属性为私有属性初始化数据,因此无需提供setter方法
2、自动装配建议使用无参构造方法创建对象(默认),如果不提供对应构造方法,请提供唯一的构造方法
使用@Qualifier注解开启指定名称装配bean
@Service
public class BookServiceImpl implements BookService {
@Autowired
@Qualifier( "bookDao")
private BookDao bookDao;
}
注意:@Qualifier注解无法单独使用,必须配合@Autowired注解使用
使用@Value实现简单类型注入
@Repository ("bookDao")
public class BookDaoImpl implements BookDao {
@Value("10")
private string connectionNum;
}
使用@PropertySource注解加载properties文件
@Configuration
@ComponentScan("com.demo")
@PropertySource("classpath:jdbc.properties")
public class SpringConfig {
}
注意:路径仅支持单一文件配置,多文件请使用数组格式配置,不允许使用通配符*
第三方bean管理
使用独立的配置类管理第三方bean
方式一:导入式
public class JdbcConfig {
@Bean
public DataSource dataSource(){
DruidDatasource ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost: 3306/spring_db");
ds.setUsername("root");
ds.setPassword("root");
return ds;
}
}
使用@Import注解手动加入配置类到核心配置,此注解只能添加一次,多个数据请用数组格式
@Configuration
@Import(JdbcConfig.class)
public class SpringConfig {
}
方式二:扫描式
使用@ComponentScan注解扫描配置类所在的包,加载对应的配置类信息
@Configuration
@ComponentScan({"com.demo.config","com.demo.service"," com.demo.dao"})
public class springConfig {
}
第三方bean依赖注入
简单类型依赖注入
public class jdbcConfig {
@Value("com.mysql.jdbc.Driver" )
private String driver;
@Value("jdbc:mysql://localhost:3306/spring_db")
private String url;
@Value("root")
private String userName;
@Value("root")
private String password;
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(userName);ds.setPassword(userName);
return ds;
}
}
引用类型依赖注入
@Bean
public DataSource dataSource(BookService bookService){
system.out.println(bookService);
DruidDataSource ds = new DruidDataSource();
//属性设置
return ds;
}
引用类型注入只需要为bean定义方法设置形参即可,容器会根据类型自动装配对象
XML配置比对注解配置
功能 | xml配置 | 注解 |
定义bean | bean标签 id属性 class属性 | @Component @Controller @Service @Repository @ComponentScan |
设置依赖注入 | setter注入( set方法) 引用/简单 构造器注入(构造方法) 引用/简单 自动装配 | @Autowired @Qualifier @Value |
配置第三方bean | bean标签 静态工厂、实例工、FactoryBeanscope属性 | @Bean |
作用范围 | scope属性 | @Scope |
生命周期 | 标准接口 init-method destroy-method | @PostConstructor @PreDestroy |