SSM-学习日记
SSM-学习日记
初识Spring,Spring的系统架构
1、Spring全家桶是一个很nb的生态,我们可以用他开发自己想要的格式的功能
Core Container是Spring的容器,java的对象交给Spring的容器来管理
AOP面向切面编程,Aspects是AOP思想的实现。不太懂,目前理解是中间商,Aspects起到承上启下的作用
DataAccess/Integration 数据访问/集成 用来做数据持久化的架构
Web 开发网页的架构
IOC与DI
IOC(控制反转)是将类属性中的对象的创建权交给外部管理,降低代码的耦合性,这里的外部是Spring,例如
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
}
Spring的注解文件
<bean id="bookDao" class="com.lrui1.dao.impl.BookDaoImpl"/>
随后可在代码中直接使用Spring容器中的对象
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
代码的耦合性大大降低
DI(依赖注入)是在一个类依赖另一个类的情况下,往该类注入相应的依赖(创建对应的对象)
java代码
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;
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
// 该方法必须创建
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
}
xml代码
<bean id="bookDao" class="com.lrui1.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="com.lrui1.service.impl.BookServiceImpl">
<!-- 配置service与dao的关系-->
<property name="bookDao" ref="bookDao"/>
</bean>
xml,property标签中,name指的是该bean中需要依赖的类名,ref是该xml文件中的对应id的bean
可理解为name = new ref
bean的基础配置
bean还有很多的属性哦,看看xml文件
<?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 id="bookDao" class="com.lrui1.dao.impl.BookDaoImpl"/>
<bean id="bookService" name="service1" class="com.lrui1.service.impl.BookServiceImpl" scope="prototype">
<!-- 配置service与dao的关系-->
<property name="bookDao" ref="bookDao"/>
</bean>
</beans>
(1)id是xml文件中唯一指定的名称
(2)class是类路径,该路径的终点就是bean的定义
(3)name可以定义多个名字,用空格逗号分号隔开
(4)scope可以定义对应bean是单例还是双例,单例—bean对象在内存空间中就1个地址,双例—bean对象在对象空间中可以有多个地址
(5)property负责依赖注入
适合交给容器管理的bean
- 表现层对象
- 业务层对象
- 数据层对象
- 工具对象
不适合交给容器管理的bean
- 封装实体域的对象——有数据要存在里面的
Bean的实例化
准备环境准备了40分钟,最后发现是字母打错了φ(* ̄0 ̄)
Spring在构造对象的时候调用的是类的无参构造方法
实例化的三种方式
(1)提供可访问的构造方法
为无参,若没有无参构造函数将抛出`BeanCreationException
(2)静态工厂实例化
<bean id="orderDao" class="org.lrui1.factory.OrderDaoFactory" factory-method="getOrderDao"></bean>
(3)实例工厂初始化Bean
先将工厂放入容器(造出来),再将工厂创建的对象放入容器
与静态工厂的区别是写两个Bean
<bean id="userDaoFactory" class="org.lrui1.factory.UserDaoFactory"></bean>
<bean id="userDao" factory-bean="userDaoFactory" factory-method="getUserDao"></bean>
(4)使用FactoryBean实例化
首先,需要放入容器的类要实现FactoryBean接口
public class UserDaoFactoryBean implements FactoryBean<UserDao> {
@Override
public UserDao getObject() throws Exception {
return new UserDaoImpl();
}
@Override
public Class<?> getObjectType() {
return UserDao.class;
}
}
在xml文件中写一个Bean即可
<bean id="userDao" class="org.lrui1.factory.UserDaoFactoryBean"></bean>
注意:该bean创造出来的对象不是userDaoFactoryBean,而是userDaoFactoryBean的getObject方法创建的对象
通过FactoryBean接口创建的对象默认是单例的,接口默认实现两个方法,要想是非单例的话得实现第三个方法
public class UserDaoFactoryBean implements FactoryBean<UserDao> {
@Override
public UserDao getObject() throws Exception {
return new UserDaoImpl();
}
@Override
public Class<?> getObjectType() {
return UserDao.class;
}
@Override
public boolean isSingleton() {
return false;
}
}
其中的isSingleton
方法,true为单例,false 为非单例
Bean生命周期
Bean的初始化正常执行,销毁却没有执行的原因是:还没来得及销毁,JVM已经退出了。对此Spring有两种销毁Bean的方式
(1)通过close()方法强制关闭容器
public class AppForLifeCycle {
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
bookDao.save();
ctx.close();
}
}
(2)通过注册关闭钩子——告诉JVM,你退出的时候不要忘记把我关闭掉
public class AppForLifeCycle {
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
ctx.registerShutdownHook();
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
bookDao.save();
}
}
close就比registerShutdownHook暴力一点
如何设置一个Bean的初始化,销毁要执行的方法呢?
方法一:在配置文件里面写
<bean id="bookDao" class="org.lrui1.dao.impl.BookDaoImpl" init-method="init" destroy-method="destroy"></bean>
方法二:实现InitializingBean和DisposableBean接口
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();
}
@Override
public void destroy() throws Exception {
System.out.println("service destroy");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("service Init");
}
}
DI相关
依赖注入除了Bean之间的关系,还有可能是Bean与简单数据类型的关系
setter注入
(1)注入类对象
<bean id="bookDao" class="org.lrui1.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="org.lrui1.service.impl.BookServiceImpl">
<property name="bookDao" ref="bookDao"/>
</bean>
(2)注入简单类型
<bean id="bookDao" class="org.lrui1.dao.impl.BookDaoImpl">
<property name="databaseName" value="mysql"/>
<property name="connectionNum" value="10"/>
</bean>
构造器注入
(1)注入类对象
public class BookServiceImpl implements BookService{
private BookDao bookDao;
public BookServiceImpl(BookDao bookDao) {
this.bookDao = bookDao;
}
}
<bean id="bookService" class="org.lrui1.service.impl.BookServiceImpl">
<constructor-arg name="bookDao" ref="bookDao"/>
</bean>
自动装配
自动装配——相当于Spring帮你在配置文件中找对应的Bean给你去注入依赖
- 按类型装配
- 按名称装配
- ···
(1)按类型装配
以下情况不能自动装配
- 配置文件中没有对应的Bean
- 自己的类没有实现Setter
- 配置文件中,要注入的Bean有多个选择(不唯一)
(2)按名称装配——是用自己Bean中需要的那个类名,去配置文件中找对应id的Bean
它的特点
1、自动装配仅仅使用与引用数据类型,不能对简单类型进行操作
2、自动装配优先级低于setter和constructer
更新于2023年2月27日
集合注入
当管理的Bean需要集合类型时,要如何注入集合?——xml配置如下
public class BookDaoImpl implements BookDao {
private int[] array;
private List<String> list;
private Set<String> set;
private Map<String,String> map;
private Properties properties;
//setter....方法省略,自己使用工具生成
}
<bean id="bookDao" class="org.lrui1.dao.impl.BookDaoImpl">
<property name="array">
<array>
<value>100</value>
<value>200</value>
<value>300</value>
</array>
</property>
<property name="list">
<list>
<value>itcast</value>
<value>itheima</value>
<value>boxuegu</value>
<value>chuanzhihui</value>
</list>
</property>
<property name="set">
<set>
<value>itcast</value>
<value>itheima</value>
<value>boxuegu</value>
<value>boxuegu</value>
</set>
</property>
<property name="map">
<map>
<entry key="country" value="china"/>
<entry key="province" value="henan"/>
<entry key="city" value="kaifeng"/>
</map>
</property>
<property name="properties">
<props>
<prop key="country">china</prop>
<prop key="province">henan</prop>
<prop key="city">kaifeng</prop>
</props>
</property>
</bean>
注意:集合注入使用的也是setter注入的方式(类似),所以bean对应的类要实现setter方法,才可以这样搞
IOC/DI配置管理第三方Bean
实际开发过程中,由于会经常采用到第三方技术,而第三方类的setter方法和构造方法不是我们能决定的,那要怎样才能实现对其的依赖注入呢?这里以Druid的DruidDataSource类为例子
xml实现管理第三方Bean
<context:property-placeholder location="jdbc.properties"/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
此配置文件中还有引入jdbc.proiperties配置对DruidDataSource进行依赖注入
加载properties文件
1、Spring中要加载properties文件,步骤如下:
(1)开辟context命名空间
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"
(2)导入文件
<context:property-placeholder location="jdbc.properties"/>
(3)调取文件中的数据
${jdbc.driver}
${jdbc.url}
${jdbc.username}
${jdbc.password}
示例properties文件如下:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/spring_db
jdbc.username=root
jdbc.password=root
形式上为键值对
2、另外开辟properties文件的好处
- 降低了耦合度
- 不将账号密码写在代码里,写在文件里方便后期修改
核心容器
创建容器的方式
类路径下创建
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
文件系统路径下创建
ApplicationContext ctx = new FileSystemXmlApplicationContext("D:\\workspace\\spring\\spring_10_container\\src\\main\\resources\\applicationContext.xml");
推荐使用类路径的创建方式,文件系统路径创建方式耦合度高,不推荐
创建好容器后,如何获取Bean对象,三种方式
//方式1
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
//方式2
BookDao bookDao = ctx.getBean("bookDao",BookDao.class);
//方式3
BookDao bookDao = ctx.getBean(BookDao.class);
容器的层次结构
BeanFactory的使用
1、java代码如下
Resource resource = new ClassPathResource("applicationContext.xml");
BeanFactory bf = new XmlBeanFactory(resource);
2、BeanFactory是顶层接口,使用BeanFactory创建的容器再加载Bean的时候具有延迟加载的特性
延迟加载——获取Bean对象的时候才创建
立即加载——容器加载的时候就会创建Bean对象
ApplicationContext就是立即加载,要想让ApplicationContext成为延迟加载,在xml文件中,配置Bean的时候将lazy-init
置为true
<?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 id="bookDao" class="com.itheima.dao.impl.BookDaoImpl" lazy-init="true"/>
</beans>
初步总结1
到目前为止,介绍完了使用xml配置基本的Bean,自己创建的Bean;
- 实例化的几种方式分别是:可访问的构造方法、静态工厂、实例工厂、实现
FactoryBean<T>
接口; - 创建容器有两种方式:类路径、文件系统路径;
- 在容器中访问创建的Bean有三种方式:按id、按id并传入返回的类、按类查找;
- Bean初始化,销毁执行的方法有两种方式:在配置文件里面直接写
init-method
和destroy-method
、实现InitializingBean和DisposableBean接口 - 关闭容器有两种方式:强制关闭和注册关闭钩子
- 配置依赖注入:setter注入、构造器注入、自动装配、集合注入
- 管理第三方Bean时:去百度找找相应的类、看看依赖注入的方式有没有限制啥的
- 加载properties文件时,先引入context空间,再加载properties文件,引用里面的键值对通过
${}
的方式
IOC/DI注解开发
众所周知,注解绝对比xml配置来的简单
1、xml和注解的类似“替代”
注解 | xml配置 |
---|---|
@SpringConfig | xml配置文件 |
@Component/@Controller/@Service/@Repository(Value) | 对应Bean标签,Value是id,默认是类首字母小写 |
@ComponentScan | <context:component-scan base-package=""/> |
@Scope | Bean中的scope |
@PostConstructor | Bean中的init-method |
@PreDestroy | Bean中的destroy-method |
@AutoWired -@Qualifier |
setter注入/构造器注入/自动装配 |
@Value | 基本类型/字符串的注入 |
@PropertySource | 加载properties文件 |
@Bean | 静态工厂、实例工厂······· |
2、注意事项
(1)@Qualifier必须搭配AutoWired一起使用
(2)@Bean是方法注解,设置一个方法的返回值为spring管理的Bean
(3)@Import导入配置类,它和@ComponentScan有且只能使用一次,可以传数组
具体代码略·······
2023年2月27日