黑马SSM笔记-spring


Spring简介

官网:https://spring.io,从官网我们可以大概了解到:
Spring能做什么:用以开发web、微服务以及分布式系统等,光这三块就已经占了JavaEE开发
的九成多。
Spring并不是单一的一个技术,而是一个大家族,可以从官网的Projects中查看其包含的所
有技术。
Spring发展到今天已经形成了一种开发的生态圈,Spring提供了若干个项目,每个项目用于完成
特定的功能。
Spring已形成了完整的生态圈,也就是说我们可以完全使用Spring技术完成整个项目的构
建、设计与开发。
Spring有若干个项目,可以根据需要自行选择,把这些个项目组合起来,起了一个名称叫全家桶,如下图所示

额外需要重点关注Spring Framework、SpringBoot和
SpringCloud
在这里插入图片描述
Spring Framework:Spring框架,是Spring中最早最核心的技术,也是所有其他技术的
基础。
SpringBoot:Spring是来简化开发,而SpringBoot是来帮助Spring在简化的基础上能
更快速进行开发。
SpringCloud:这个是用来做分布式之微服务架构的相关开发。
官方下载地址 : https://repo.spring.io/libs-release-local/org/springframework/spring/
GitHub : https://github.com/spring-projects

优点

1、Spring是一个开源免费的框架 , 容器 .

2、Spring是一个轻量级的框架 , 非侵入式的 .

3、控制反转 IoC , 面向切面 Aop

4、对事物的支持 , 对框架的支持
Spring Framework的5版本目前没有最新的架构图,而最新的是4版本,所以接下来主要研究的
是4的架构图


(1)核心层
Core Container:核心容器,这个模块是Spring最核心的模块,其他的都需要依赖该模块
(2)AOP层
AOP:面向切面编程,它依赖核心层容器,目的是在不改变原有代码的前提下对其进行功能增强
Aspects:AOP是思想,Aspects是对AOP思想的具体实现
(3)数据层
Data Access:数据访问,Spring全家桶中有对数据访问的具体实现技术
Data Integration:数据集成,Spring支持整合其他的数据层解决方案,比如Mybatis
Transactions:事务,Spring中事务管理是Spring AOP的一个具体实现,也是后期学习的
重点内容
(4)Web层
这一层的内容将在SpringMVC框架具体学习
(5)Test层
Spring主要整合了Junit来完成单元测试和集成测试

IOC,IOC容器、Bean、DI

使用对象时,在程序中不要主动使用new产生对象,转换为由外部提供对象
这种实现思就是Spring的一个核心概念
IOC(Inversion of Control)控制反转是一种设计思想,DI(依赖注入)是实现IoC的一种方法,业务层要用数据层的类对象,以前是自己new的
现在自己不new了,交给别人[外部]来创建对象
别人[外部]就反转控制了数据层对象的创建权
这种思想就是控制反转。
Spring技术对IOC思想进行了实现
Spring提供了一个容器,称为IOC容器,用来充当IOC思想中的"外部"
IOC思想中的别人[外部]指的就是Spring的IOC容器
依赖注入:
在容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入
业务层要用数据层的类对象,以前是自己new的
现在自己不new了,靠别人[外部其实指的就是IOC容器]来给注入进来
这种思想就是依赖注入
介绍完Spring的IOC和DI的概念后,我们会发现这两个概念的最终目标就是:充分解耦

核心概念

IOC,DI思想

IOC:控制反转,控制反转的是对象的创建权
DI:依赖注入,绑定对象与对象之间的依赖关系

IOC容器

Spring创建了一个容器用来存放所创建的对象,这个容器就叫IOC容器

bean

容器中所存放的一个个对象就叫Bean或Bean对象

入门案例实现

思路分析

1.创建Maven的java项目
2.pom.xml添加Spring的依赖jar包
3.创建BookService,BookServiceImpl,BookDao和BookDaoImpl四个类
4.resources下添加spring配置文件,并完成bean的配置
5.使用Spring提供的接口完成IOC容器的创建
6.从容器中获取对象进行方法调用
步骤1:创建Maven项目

步骤2:添加Spring的依赖jar包
pom.xml

步骤3:添加案例中需要的类
创建BookService,BookServiceImpl,BookDao和BookDaoImpl四个类

public interface BookDao {
public void save();
}
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
}
public interface BookService {
public void save();
}
public class BookServiceImpl implements BookService {
private BookDao bookDao = new BookDaoImpl();
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}

步骤4:添加spring配置文件
resources下添加spring配置文件applicationContext.xml,并完成bean的配置

步骤5:在配置文件中完成bean的配置

注意事项:bean定义时id属性在同一个上下文中(配置文件)不能重复
步骤6:获取IOC容器
使用Spring提供的接口完成IOC容器的创建,创建App类,编写main方法

public class App {
public static void main(String[] args) {
//获取IOC容器
ApplicationContext ctx = new
ClassPathXmlApplicationContext("applicationContext.xml");
}
}

步骤7:从容器中获取对象进行方法调用

public class App {
public static void main(String[] args) {
//获取IOC容器
ApplicationContext ctx = new
ClassPathXmlApplicationContext("applicationContext.xml");
// BookDao bookDao = (BookDao) ctx.getBean("bookDao");
// bookDao.save();
BookService bookService = (BookService) ctx.getBean("bookService");
bookService.save();
}
}

步骤8:运行程序
测试结果为:

Spring的IOC入门案例已经完成,但是在BookServiceImpl的类中依然存在BookDaoImpl对象的
new操作,它们之间的耦合度还是比较高,这块该如何解决,就需要用到下面的DI:依赖注入。
步骤1: 去除代码中的new
在BookServiceImpl类中,删除业务层中使用new的方式创建的dao对象

步骤2:为属性提供setter方法
在BookServiceImpl类中,为BookDao提供setter方法

public class BookServiceImpl implements BookService {
//删除业务层中使用new的方式创建的dao对象
private BookDao bookDao;
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
//提供对应的set方法
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
}

步骤3:修改配置完成注入

<?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
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--bean标签标示配置bean
id属性标示给bean起名字
class属性表示给bean定义类型
-->
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
<!--配置server与dao的关系-->
<!--property标签表示配置当前bean的属性
name属性表示配置哪一个具体的属性
ref属性表示参照哪一个bean
-->
<property name="bookDao" ref="bookDao"/>
</bean>
</beans>

IOC相关

bean基础配置

对于bean的配置中,主要会讲解bean基础配置, bean的别名配置, bean的作用范围配置(重点),这三部
分内容:
对于bean的基础配置,在前面的案例中已经使用过:
其中,bean标签的功能、使用方式以及id和class属性的作用,我们通过一张图来描述下

这其中需要大家重点掌握的是:bean标签的id和class属性的使用。

bean的name属性

环境准备好后,接下来就可以在这个环境的基础上来学习下bean的别名配置,
首先来看下别名的配置说明:

<?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
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--name:为bean指定别名,别名可以有多个,使用逗号,分号,空格进行分隔-->
<bean id="bookService" name="service service4 bookEbi"
class="com.itheima.service.impl.BookServiceImpl">
<property name="bookDao" ref="bookDao"/>
</bean>
<!--scope:为bean设置作用范围,可选值为单例singloton,非单例prototype-->
<bean id="bookDao" name="dao" class="com.itheima.dao.impl.BookDaoImpl"/>
</beans>

根据名称容器中获取bean对象

public class AppForName {
public static void main(String[] args) {
ApplicationContext ctx = new
ClassPathXmlApplicationContext("applicationContext.xml");
//此处根据bean标签的id属性和name属性的任意一个值来获取bean对象
BookService bookService = (BookService) ctx.getBean("service4");
bookService.save();
}
}

bean依赖注入的ref属性指定bean,必须在容器中存在
获取bean无论是通过id还是name获取,如果无法获取到,将抛出异常
NoSuchBeanDefinitionException

bean的作用范围scope


验证IOC容器中对象是否为单例:
bean为单例的意思是在Spring的IOC容器中只会有该类的一个对象
bean对象只有一个就避免了对象的频繁创建与销毁,达到了bean对象的复用,性能高
方法:同一个bean获取两次,将对象打印到控制台,看打印出的地址值是否一致
结论:默认情况下,Spring创建的bean对象都是单例的
配置bean为非单例
在Spring配置文件中,配置scope属性来实现bean的非单例创建
在Spring的配置文件中,修改的scope属性

<bean id="bookDao" name="dao" class="com.itheima.dao.impl.BookDaoImpl"
scope=""/>

将scope设置为singleton

<bean id="bookDao" name="dao" class="com.itheima.dao.impl.BookDaoImpl"
scope="singleton"/>

结论,使用bean的scope属性可以控制bean的创建是否为单例:
singleton默认为单例
prototype为非单例
注:封装类实例对象不适合交给容器管理,会引发线程安全问题,而表现层,业务层,数据层和工具对象可以交给容器管理,因为调用完成后会进行销毁,不存在线程安全问题。
bean本质上就是对象,对象在new的时候会使用构造方法完成,那创建bean也是使用构造方法完成的。

bean实例化

1.用无参构造方法来实例化对象
    //用无参构造方法来实例化对象
public BookDaoImpl() {
    System.out.println("book dao constructor is running ....");
}
2.静态工厂创建对象

public class OrderDaoFactory {
    public static OrderDao getOrderDao(){
        System.out.println("factory setup....");
        return new OrderDaoImpl();
    }
}



```java
<bean id="orderDao" class="factory.OrderDaoFactory" factory-method="getOrderDao"/>
3.使用实例工厂实例化bean
        //创建实例工厂对象(main方法中)
        UserDaoFactory userDaoFactory = new UserDaoFactory();
        //通过实例工厂对象创建对象
        UserDao userDao = userDaoFactory.getUserDao();
        userDao.save();
public class UserDaoFactory {
    public UserDao getUserDao(){
        return new UserDaoImpl();
    }
}
<bean id="userFactory" class="factory.UserDaoFactory"/>
 
<bean id="userDao" factory-method="getUserDao" factory-bean="userFactory"/>
4.使用FactoryBean实例化bean
public class UserDaoFactoryBean implements FactoryBean<UserDao> {
//代替原始实例工厂中创建对象的方法
public UserDao getObject() throws Exception {
return new UserDaoImpl();
}
//返回所创建类的Class对象
public Class<?> getObjectType() {
return UserDao.class;
}
}
<bean id="userDao" class="factory.UserDaoFactoryBean"/>

bean的生命周期

法一

1.添加初始化和销毁方法

public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
//表示bean初始化对应的操作
public void init(){
System.out.println("init...");
}
//表示bean销毁前对应的操作
public void destory(){
System.out.println("destory...");
}
}

2.在配置文件中配置生命周期

<bean id="bookDao" class="dao.impl.BookDaoImpl" init-method="init"
destroy-method="destory"/>

3.直接关闭容器

ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//调用ctx的close方法
ctx.close();
法二

1.添加钩子

 ctx.registerShutdownHook()

2.修改BookServiceImpl类,添加两个接口InitializingBean, DisposableBean并实现接口中的 两个方法afterPropertiesSet和destroy

public class BookServiceImpl implements BookService, InitializingBean,
DisposableBean {
private BookDao bookDao;
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
public void destroy() throws Exception {
System.out.println("service destroy");
}
public void afterPropertiesSet() throws Exception {
System.out.println("service init");
}
}

Spring DI注入

DI(Dependency Injection)依赖注入是一种通过外部注入对象的依赖关系来解决对象之间依赖关系的方法。DI的作用如下:

降低代码复杂度
降低对象之间的耦合性
方便对象的单元测试和集成测试
Spring DI的实现原理主要有以下几种方式。

构造函数注入

构造函数注入是一种常见的DI方式,它通过对象的构造函数来注入依赖关系。示例如下

public class BookServiceImpl implements BookService {
    private BookDao bookDao;
 
    public BookServiceImpl(BookDao bookDao) {
        this.bookDao = bookDao;
    }
 
    // methods
}

在上面的示例中,BookServiceImpl类的构造函数接收一个BookrDao实例,并将其赋值给类的成员变量bookDao。

Setter方法注入

Setter方法注入是另一种常见的DI方式,它通过对象的Setter方法来注入依赖关系。示例如下:

public class UserServiceImpl implements UserService {
    private UserDao userDao;
 
    public void setUserDao(UserDao userDao) {
       this.userDao = userDao;
    }
 
    // methods
}

在上面的示例中,UserServiceImpl类的setUserDao方法接收一个UserDao实例,并将其赋值给类的成员变量userDao。

接口注入

public interface UserService {
    void addUser(User user);
}
 
public class UserServiceImpl implements UserService {
    private UserDao userDao;
 
    public UserServiceImpl(UserDao userDao) {
        this.userDao = userDao;
    }
 
    @Override
    public void addUser(User user) {
        userDao.addUser(user);
    }
}

自动装配

自动装配是一种比较方便的DI方式,它通过容器自动查找并注入依赖关系。Spring DI提供了多种自动装配方式,包括按名称、按类型、按注解等方式。示例如下:

@Service
public class UserServiceImpl implements UserService {
   @Autowired
    private UserDao userDao;
 
    // methods
}

Spring纯注解开发

Spring的开发大体可分为两类:XML配置和注解开发。

配置文件

配置文件分为两种方式:XML配置文件、Config配置类
Config配置类:
自己创建一个Config类,在创建的类上面加上@Configuration注解,该类就变为Spring的配置类。

@Configuration
@ComponentScan({"com.zyh.pojo","com.zyh.service"})//扫描包下的bean对象
//@Import(MyConfig2.class) 导入其他配置类
public class SpringConfig {
    @Bean
    public People people(){
        return new People();
    }
}

这些代码就创建了一个基础的配置文件。实际上是取代了xml当中的以下代码:
其中上图配置类中的@ComponentScan(“包名”)等同于xml方法中中配置文件中的<context:component-scan base-package=“com.zyh.pojo”/>。
@Configuration等同于其余代码。
如上代码所示,一个简单的配置类就创建好了,也就相当于创建好了一个容器。

创建并注入bean

方法1:

@Configuration
@ComponentScan({"com.zyh.pojo","com.zyh.service"})
//@Import(MyConfig2.class) 导入其他配置类
public class SpringConfig {
    @Bean
    public People people(){
        return new People();
    }
}

方法2:在实体类上加@Component

在实体类上加@Component ,config配置文件扫描到该注解会自动创建bean对象。

@Component("user")  // 不加括号名,则名字默认未类名(首字母小写)
// 相当于配置文件中 <bean id="user" class="当前注解的类"/>
public class User {
    @Value("猪猪")
    // 相当于配置文件中 <property name="name" value="猪猪"/>
    public String name;
    //要给出getter方法,但可以不用给出setter方法了
    public String getName() {
        return name;
    }
}

@component的衍生注解:
1.@Controller:用于表现层bean定义
2.@Repository:用于数据层(dao层)bean定义
3.@Service:用于业务层bean定义

依赖注入

使用@Value(“名称”)进行赋值。
@Autowired:自动按类型装配
@Qualifier(“people”) :注入指定的bean对象,当有多个相同的类型时,就要用这种方式。
例:User类中添加了People类作为属性。

@Component("user")
// 相当于配置文件中 <bean id="user" class="当前注解的类"/>
public class User {
    @Autowired   // 自动按类型装配
    @Qualifier("people")  // 注入指定的bean对象,没有重复时不需要写
    private People people;
    @Value("小明")
    private String name;
    //要给出getter方法,但可以不用给出setter方法了
    public String getName() {
        return name;
    }
    public void save(){
        people.say();
    }
}
注解读取properties文件

在配置类上添加@PropertySource注解

@Configuration
@ComponentScan("包名")
@PropertySource("配置文件.properties")
public class SpringConfig {
}

如果读取的properties配置文件有多个,可以使用@PropertySource的属性来指定多个
例:@PropertySource({“jdbc.properties”,“xxx.properties”}

注解开发管理第三方bean

1.在pom文件中导入第三方bean坐标(druid坐标)

对于数据源的bean,我们新建一个JdbcConfig配置类,并把数据源配置到该类下。

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;
}
}

3.将该配置类引入到spring配置类中
法一:使用包扫描引入

@Configuration
@ComponentScan("config")
public class SpringConfig {
}

在JdbcConfig上添加配置注解@configuration
法二:
在spring配置类中引入
使用@Import引入

@Configuration
//@ComponentScan("config")
@Import({JdbcConfig.class})//@Import参数需要的是一个数组,可以引入多个配置类。
 
public class SpringConfig {
}
注解开发实现第三方注入

1.在配置类中利用@value注解配置

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("password")
private String password;
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(userName);
ds.setPassword(password);
return ds;
}
}

总结与xml配置的区别

Spring整合mybatis,junit

1.在pom文件中导入以下依赖
spring-context druid mybatis mysql-connector-java spring-jdbc mybatis-spring
2.创建Spring配置类

//配置类注解
@Configuration
//包扫描,主要扫描的是项目中的AccountServiceImpl类
@ComponentScan("...")
public class SpringConfig {
}

3.创建数据源的配置类

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
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(userName);
ds.setPassword(password);
return ds;
}
}

4.主配置类中读properties并引入数据源配置类

@Configuration
@ComponentScan("...")
@PropertySource("classpath:jdbc.properties")
@Import(JdbcConfig.class)
public class SpringConfig {
}

5.创建Mybatis配置类并配置SqlSessionFactory

public class MybatisConfig {
//定义bean,SqlSessionFactoryBean,用于产生SqlSessionFactory对象
@Bean
public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){
SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean();
//设置模型类的别名扫描
ssfb.setTypeAliasesPackage("domain");
//设置数据源
ssfb.setDataSource(dataSource);
return ssfb;
}
//定义bean,返回MapperScannerConfigurer对象
@Bean
public MapperScannerConfigurer mapperScannerConfigurer(){
MapperScannerConfigurer msc = new MapperScannerConfigurer();
msc.setBasePackage("com.itheima.dao");
return msc;
}
}

6.主配置类中引入Mybatis配置类

@Configuration
@ComponentScan("com.itheima")
@PropertySource("classpath:jdbc.properties")
@Import({JdbcConfig.class,MybatisConfig.class})
public class SpringConfig {
}

Spring_AOP

Aspect Oriented Programming
意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。
AOP作用: 在不惊动原始设计的基础上为其进行功能增强,前面咱们有技术就可以实现这样的功能即代理模式

AOP切入点表达式

//描述方式一:执行dao包下的BookDao接口中的无参数update方法
execution(void dao.BookDao.update())
描述方式二:执行dao.impl包下的BookDaoImpl类中的无参数update方法
execution(void dao.impl.BookDaoImpl.update()

切入点表达式标准格式:动作关键字(访问修饰符 返回值 包名.类/接口名.方法名(参数) 异常 名)

execution(public User service.UserService.findById(int))

spring_事务管理

1.在业务层接口上添加spring事务管理

public interface AccountService {
    //配置当前接口方法具有事务
    @Transactional
    public void transfer(String out,String in ,Double money) ;
}
//配置事务管理器,mybatis使用的是jdbc事务
    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource){
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(dataSource);
        2.设置事务管理器
        return transactionManager;
    }

2.设置事务管理器

@Configuration
@ComponentScan("com.itheima")
@PropertySource("classpath:jdbc.properties")
@Import({JdbcConfig.class,MybatisConfig.class})
//开启注解式事务驱动
@EnableTransactionManagement
public class SpringConfig {
}


上面这些属性都可以在@Transactional注解的参数上进行设置。

事务传播行为:事务协调员对事务管理员所携带事务的处理态度。 具体如何解决,就需要用到之前我们没有说的propagation属性。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值