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-methoddestroy-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日


posted @ 2023-02-14 21:32  lrui1  阅读(14)  评论(0编辑  收藏  举报