前言:学习路线
Spring就是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架!
第一章:纯手写
一、核心概念
什么是IoC、IoC容器、bean、DI ?
IoC:对象创建控制权由程序转移到IoC容器的控制反转思想。
IoC容器:创建管理对象的容器。
bean:IoC容器中被创建管理的对象。
DI:IoC容器中建立bean之间依赖关系的过程。
二、IoC入门实例
第一步:在pom.xml添加spring-context依赖
第二步:在resources创建spring Config
只有成功添加了spring-context依赖才会显示出spring Config选项
第三步:在spring config内 创建bean
第四步:初始化IoC容器,并获取bean
三、DI入门实例
第一步:解耦&添加setter方法
此setter方法是容器在调用,往service层传递对象
第二步:配置service与dao的关系
将dao注入到service
四、bean基础配置
总:bean基础配置id 、class;别名name;作用范围scope。
bean别名配置
在spring配置文件内依赖注入 ref时可以使用别名;在调用容器获取bean时也可以使用别名;
写id更规范。
bean的作用范围
通过直接打印调用容器内的对象的地址来判断获取的对象是同一个对象还是不同的对象。
bean的作用范围scope:控制我们创建实例的数量;
五、bean实例化<4>
1、构造方法(常用)
bean本质是对象,创建bean使用构造方法完成。
spring创建bean调用的是无参构造方法。
spring报错,由下往上看。
无论我把无参构造方法调整位置,最终打印出来的首先就是无参构造方法里面打印的信息。说明spring在创建bean时是调用无参构造方法完成对象的创建和初始化。然后再调用实例化对象的方法。
注意:如果未手写无参构造方法,会自动调用默认的无参构造方法。
但是如果手写了构造方法,无参的,则会优先调用手写的;如果手写了有参构造方法,也不会再调用默认的无参构造方法,但倘若没有另外手写无参构造方法,只能调用有参构造方法,会报错:NoSuchMethodException。此部分和java创建对象时的知识连起来的。
2、静态工厂(了解)
- 调用静态工厂方法创建 bean 是将对象创建的过程封装到静态方法中 , 当客户端需要对象时 , 只需要简单地调用静态方法 , 而不需要关心创建对象的细节。
- 要声明通过静态方法创建的 bean , 需要在 bean 的 class 属性里面指定拥有该工厂的方法的类 , 同时在 factory-method 属性里指定工厂方法的名称。最后 , 使用 <constructor-arg> 元素为该方法传递方法参数。
public class OrderDaoFactory {
public static OrderDao getOrderDao(){
return new OrderDaoImpl();
}
}
<bean id="orderdao" class="com.itheima.factory.OrderDaoFactory"
factory-method="getOrderDao"/>
3、实例工厂(了解)
实例工厂
public class UserDaoFactory {
//注意此处采用非静态方法创建对象
public UserDao getUserDao(){
System.out.println("此处是调用非静态工厂创建对象的方法");
return new UserDaoImpl();
}
}
配置
3、通过实例工厂创建对象 -->
<bean id="userdaofactory"
class="com.itheima.factory.UserDaoFactory"/>
<bean id="userdao" factory-method="getUserDao"
factory-bean="userdaofactory"/>
弊端:要通过实例工厂对象的方法创建对象,在配置时需要多余配置无意义的bean。
4、Factory Bean(重要)
FactoryBean
//继承接口并且要填写范型-要造的对象
public class UserDaoFactoryBean implements FactoryBean<UserDao> {
//实现接口内的抽象方法(3个))
//1、代替原始实例工厂中创建对象的方法
public UserDao getObject() throws Exception {
System.out.println("此处调用factorybean方式创建对象");
return new UserDaoImpl();
}
//2、说明对象的类型
public Class<?> getObjectType() {
return UserDao.class;
}
//3、创建的Bean是单例还是非单例
public boolean isSingleton() {
return false;
}
}
配置
<bean id="ikun" class="com.itheima.factory.UserDaoFactoryBean"/>
六、Bean生命周期
Bean生命周期控制
方法一:提供生命周期控制方法&配置
public class BookDaoImpl implements BookDao{
public void save(){
System.out.println("此处是对Dao数据层接口的实现类");
}
//表示Bean初始化对应的操作
public void init(){
System.out.println("bean初始化");
}
//表示Bean销毁对应的操作
public void destory(){
System.out.println("bean销毁");
}
配置(属性:init-method、destroy-method)
<bean id="bookdao1" name="ikun;bkdao2" class="com.itheima.dao.impl.BookDaoImpl" init-method="init" destroy-method="destory"/>
方法二:实现InitializingBean, DisposableBean接口
public class BookDaoImpl implements BookDao, InitializingBean, DisposableBean {
public void save(){
System.out.println("此处是对Dao数据层接口的实现类");
}
public void destroy() throws Exception {
System.out.println("service destory");
}
public void afterPropertiesSet() throws Exception {
System.out.println("service init");
}
}
七、依赖注入
向一个类中传递数据,咋传?
依赖注入方式:setter注入、构造器注入; 依赖注入的数据类型:引用类型、简单类型(基本数据类型与string);
1、setter注入
引用类型
在Bean中定义引用类型属性并提供可访问的Set方法
public class BookServiceImpl implements BookService {
private BookDao bookDao;
private UserDao userDao;
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
//通过以上方法 将spring的Bean通过Set方法传入到此类中
public void save(){
bookDao.save();
userDao.save();
System.out.println("此处是bookservice的实现类");
}
配置中使用property标签ref属性注入引用类型对象
<bean id="serviceDao"class="com.itheima.service.impl.BookServiceImpl">
<property name="bookDao" ref="bookDaoikun"/>
<property name="userDao" ref="userDaoikun"/>
</bean>
简单类型
bean
public class BookDaoImpl implements BookDao {
//普通类型注入数据
private int sumnum;
private String DBname;
public void setSumnum(int sumnum) {
this.sumnum = sumnum;
}
public void setDBname(String DBname) {
this.DBname = DBname;
}
配置--使用value属性
<bean id="bookDaoikun" class="com.itheima.dao.impl.BookDaoImpl">
<property name="sumnum" value="100"/>
<property name="DBname" value="redis"/>
</bean>
2、构造器注入(了解)
和set没啥区别 就是在bean内将set方法换成构造器,将配置的标签换成constructor-arg
引用类型
在Bean中定义引用类型属性并提供可访问的S构造器方法
public class BookServiceImpl implements BookService {
private BookDao bookDao;
private UserDao userDao;
//此处是构造器方法 和Set都是个方法嘛
//注意在constructor内name就是构造方法的形参,ref是不同bean的id
public BookServiceImpl(BookDao bookDao, UserDao userDao) {
this.bookDao = bookDao;
this.userDao = userDao;
}
//通过以上方法 将spring的Bean通过构造器方法传入到此类中
public void save(){
userDao.save();
bookDao.save();
System.out.println("此处是bookservice的实现类");
}
配置 constructor-arg标签 name ref属性(name就是构造方法的形参,ref是不同bean的id)
<bean id="serviceDao"class="com.itheima.service.impl.BookServiceImpl">
<constructor-arg name="bookDao" ref="bookDaoikun"/>
<constructor-arg name="userDao" ref="userDaoikun"/>
</bean>
普通类型
bean
public class BookDaoImpl implements BookDao {
private int num;
private String DBname;
public BookDaoImpl(int num, String DBname) {
this.num = num;
this.DBname = DBname;
}
public void save(){
System.out.println("此处是BookDao的实现类:");
System.out.println("使用构造器引入普通类型" + num +"," + DBname);
}
配置
<bean id="bookDaoikun" class="com.itheima.dao.impl.BookDaoImpl">
<constructor-arg name="num" value="1011"/>
<constructor-arg name="DBname" value="mysql"/>
</bean>
由于配置内的name要和bean内的构造器方法的形参一致,造成高度耦合,有type、index解耦
3、使用选择
八、自动装配
IoC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程叫做xxxx。
自动装配方式:
按类型:byType(常用)
按名称:byName (此处的name指的是被依赖注入的bean的id名)(少用-名称耦合度大)
按构造器方法(不常用)
bean内还是直接写引用的对象以及set注入方法
public class UserDaoImpl implements UserDao {
//在UserDao内引用bookDao对象
private BookDao bookDao;
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
System.out.println("显示此句子说明采用了set注入二楼");
}
配置不用写property标签,直接在bean标签内写autowire(注意id写标准,和bean内引用的对象名一样)
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
<bean id="userDaoikun" class="com.itheima.dao.impl.UserDaoImpl" autowire="byName"/>
九、集合注入(了解-用的极少)
了解一下配置格式就好了
十、案例:数据源对象管理
导入druid(数据库连接池)依赖坐标
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
配置数据源对象作为spring管理的bean
<!-- 第三方的bean,掌握基本的管理的方法-->
<bean id="dataSource"class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/spring_db"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
管理方法:
最基本的配置驱动Driver、URL、username、password。不同的第三方数据源命名有出入,大体一致。
十一、spring加载properties文件
加载properties文件的目的是将一些敏感信息封装,同时也可以信息直接使用变量名代替,方便多次调用。
1、开启context命名空间
在spring的配置文件applicationContext头文件中粘贴修改操作。
2、使用context空间加载properties文件
接着在applicationContext添加
<context:property-placeholder location="jdbc.properties"/>
规范格式:
<context:property-placeholder location="classpath:*.properties"/>
但这种只会在resources文件中读取
要想还能够读取其他文件夹内的jar包
更规范:
<context:property-placeholder location="classpath*:*.properties"/>
3、使用属性占位符${}读取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>
十二、容器
获取容器的俩种方式:
获取bean:
容器类层次:
十三、核心容器总结
1、spring核心接口与实现类
2、bean的标签配置
3、依赖注入的属性配置
第二章:注解开发
一、注解开发定义bean
对于每一个类都需要在spring配置文件中定义bean,有的bean只需要定义一下标签id、class就好了,有的甚至需要写很多属性,set注入就要写很多property属性。那么就会导致配置文件很乱。对于只需要简单获取bean的类,采用注解开发,更简洁。
1、实现类中写上注解@Component("bean名称(和获取的bean定义的名称一致)")
1、
@Component("bookDao")
public class BookDaoImpl implements BookDao {
2、
@Component("bookService")
public class BookServiceImpl implements BookService {
2、spring配置文件通过组件扫描加载bean(会扫描package下辖的所有实现类)
<context:component-scan base-package="com.itheima"/>
衍生注解: Component可以直接被代替(达到见文知作用)
二、纯注解开发
写实现类的注解-写配置类-写获取容器及bean
基本操作:将配置文件用专门写的配置类代替(配置类写上代替的配置文件以及扫描范围);其余的各个实现类中写上注解;使用的spring容器还是ApplicationContext接口,换成实现类AnnotationConfigApplicationContext()传参数为配置类。
1、 配置类:(一般创建在com.xxxx下)(各个标签的作用如上图)
@Configuration
@ComponentScan("com.itheima")
public class SpringConfig {
}
2、各个实现类的注解如上所讲。
3、获取容器并获取容器的bean(注意容器实现类的参数由配置文件改为配置类!)
public class AppForAnnotation {
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
bookDao.save();
BookService bookService = (BookService) ctx.getBean("bookService");
bookService.save();
}
三、bean作用范围与生命周期
作用范围:添加标签@Scope与单例还是非单例
@Service("bookService")
1、非单例 @Scope("prototype")
2、单例 @Scope("singleton")
public class BookServiceImpl implements BookService {
public void save(){
System.out.println("此处是bookservice的实现类");
}
生命周期:使用@PostConstruct、@PreDestroy
//bean生命周期添加注解 不用接口
@PostConstruct
public void init(){
System.out.println("此处是构造bean之后的初始化");
}
@PreDestroy
public void destory(){
System.out.println("此处是销毁bean之前的操作");
}
四、依赖注入
注解开发目的就是加速开发,对于传统的setter、构造器注入,不做。
自动装配方式
引用类型:
1、基本操作:只需要在被注入的bean上面加入@Autowired;由于自动装配默认采用按类型,所以当有多个相同类型实现类时,就需要再添加@Qualifier(bean名称)来按名称区分。
2、注入方法setter可省略。采用java反射机制,暴力赋值,所以不再需要setter方法注入。
@Autowired //此句功能就是自动装配 在配置文件层面将dao注入到service
@Qualifier("bookDao2")
private BookDao bookDao;
//public void setBookDao(BookDao bookDao) {
// this.bookDao = bookDao;
//}
简单类型:
是在引用类型自动装配的基础上,在被注入的bean实现类里面添加要注入的值!
@Repository("bookDao2")
public class BookDaoImpl2 implements BookDao {
@Value("nishinadendan")
private String name;
public void save(){
System.out.println("此处是bookDao的实现类2" + name);
}
}
五、加载properties文件
1、properties文件中写入信息
2、配置内中写入标签@PropertySource,参数是properties文件名称
对于多文件,数组形式写入。注解开发此处不支持通配符*
@Configuration
@ComponentScan("com.itheima")
@PropertySource("jdbc.properties") //配置类中添加properties文件
public class SpringConfig {
}
3、被注入的值 直接使用${}填充
@Repository("bookDao2")
public class BookDaoImpl2 implements BookDao {
@Value("${jdbc.bb}")
private String name;
public void save(){
System.out.println("此处是bookDao的实现类2" + name);
}
}
六、第三方bean管理与依赖注入
管理
1、定义一个方法获得想要管理的对象
2、添加@bean,表示当前方法的返回值是一个bean
采用中央式配置类,第三方bean单独写入一个配置类,在spring配置类中@Import。
方式二:扫描式(比较乱--不推荐使用)
每个独立的第三方配置类都要@Configuration;然后在spring核心配置类使用@ComponentScan("com.itheima") 扫描到每一个第三方配置类。
依赖注入
总结:
要会哪些东西?
1、基础:在maven项目基础上,会写pom.xml的依赖;会写spring核心配置文件applicationContext.xml内的bean;
2、总体的话就是两大部分:纯手工配置 & 纯注解开发
基本原理就是:
配置文件 & 配置类
配置文件内配置bean & 配置类写@标签
依赖注入
配置第三方bean