SSM学习:SpringIoC容器管理配置的三种方式

目录

一、基于XML配置方式组件管理

配置之前:

开始配置!

1. 创建新的maven工程

2. 父工程导入所需基础依赖

 3. 父工程目录下创建相关子工程

1. 基于无参构造函数的组件信息声明配置

 1.1 准备组件类

1.2 创建相关配置文件

1.3 在XML文件中声明相关的bean标签

2. 基于静态工厂方法的的组件信息声明配置

 2.1 创建相关组件类

 2.2 在XML文件中声明相关的bean标签

3. 基于实例工厂方法的XML的组件信息声明配置

3.1 创建相关组件类

3.2 在XML文件中声明相关的bean标签

4. 基于单个构造参数的组件依赖注入配置

4.1 准备组件类

4.2 编写配置文件

5. 基于多个构造参数的组件依赖注入配置 

5.1 准备组件类

5.2 编写配置文件

6. 基于Setter方法的组件依赖注入配置  

6.1 准备组件类

6.2 编写配置文件

7. IoC和DI配置完成后!创建IoC容器并使用

7.1. 创建IoC容器

7.2 从IoC容器中获取组件实例

组件Bean:作用域和周期方法配置

周期方法:

组件类的周期方法:

周期方法的声明:

作用域: 

作用域可选值:

配置文件:

FactoryBean接口:简化工厂模式的Bean组件配置

创建待实例的类

创建实例的工厂类:

配置文件:

二、基于注解配置方式组件管理

常见注解:

配置扫描包:

组件Bean:作用域和周期方法注解

周期方法声明:

Bean组件中的引用类型属性赋值:

Bean组件中的基本类型属性赋值: 

三、基于配置类方式组件管理

1. 创建config包,创建Configuration配置类

2. 创建配置类的IoC容器:

3. 外部组件的声明 

4. @Import拓展


本文章内容都是跟着黑马的学习笔记~大家有需要也可以直接去看黑马在B站发布的SSM视频

一、基于XML配置方式组件管理

配置之前:

        不考虑反射,Java中有四种实例化方式。通过构造函数实例化有“无参构造函数”和“有参构造函数”两种方式。通过工厂模式实例化有“静态工厂”和“非静态工厂”两种方式,共四种。不同的对象实例化方式IoC的配置方法不同。

        因有参构造实例化涉及了DI(依赖注入),故先不考虑有参构造的配置方式。

开始配置!

        为了防止重复导入相关依赖,首先创建一个父工程,用于导入所需依赖。其余操作再创建子工程进行。

1. 创建新的maven工程

        工程创建完成后,修改pom文件。

        随后删去父工程的src文件夹

2. 父工程导入所需基础依赖

        刷新maven工程即可导入相关依赖

 3. 父工程目录下创建相关子工程

        因为子工程继承了父工程的配置文件,所以子工程无需重复引入依赖~ 

1. 基于无参构造函数的组件信息声明配置

 1.1 准备组件类

        com.目录下创建一个包:ioc_01

包下创建组件类:SadComponent

package com.landy.ioc_01;/**
 * ClassName : SadComponent
 * Package:com.landy.ioc_01
 * Description :
 * Author : LandyLee
 * Create : 2024/5/5 - 22:35
 * Version : v1.0
 *
 */public class SadComponent {
     // 默认包含无参构造函数
     public void doWork(){
         System.out.println("SadComponent.doWork");
     }
}
1.2 创建相关配置文件

        resources文件夹下创建Spring配置文件:New -> XML Configuration File -> Spring Config 即可直接创建含有Spring配置信息的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">

</beans>
1.3 在XML文件中声明相关的bean标签
<!--  1. 使用无参构造函数实例化的组件  -->
    <!-- bean标签:一个组件对象 id:组件的唯一标识 class:组件的类全限定名   -->
    <!-- 将同一组件类声明两个组件信息,回市里两个组件对象   -->
    <bean id="sadComponent" class="com.landy.ioc_01.SadComponent"/>

2. 基于静态工厂方法的的组件信息声明配置

 2.1 创建相关组件类
package com.landy.ioc_01;

/**
 * ClassName : ClientService
 * Package:com.landy.ioc_01
 * Description :
 * Author : LandyLee
 * Create : 2024/5/5 - 22:51
 * Version : v1.0
 */
public class ClientService {
    private static ClientService clientService = new ClientService();
    private ClientService() {}

    public static ClientService createInstance() {
        return clientService;
    }
}
 2.2 在XML文件中声明相关的bean标签

        factory-method一定要绑定静态方法!

    <!-- 2. 静态工厂类进行IoC配置   -->
    <!-- id:组件的唯一标识 class:组件的类全限定名 factory-method:静态工厂方法名   -->
    <bean id="clientService" class="com.landy.ioc_01.ClientService" factory-method="createInstance"></bean>

3. 基于实例工厂方法的XML的组件信息声明配置

3.1 创建相关组件类
package com.landy.ioc_01;

public class ClientServiceImplclientService {

}
package com.landy.ioc_01;

public class DefaultServiceLocator {

    private static ClientServiceImplclientService clientService = new ClientServiceImplclientService ();

    public ClientServiceImplclientService createInstance() {
        return clientService;
    }
}
3.2 在XML文件中声明相关的bean标签
     <!-- 3. 实例工厂进行IoC配置   -->
    <!-- 配置工厂类的组件信息:相当于先把工厂实例创建出来   -->
    <bean id="defaultServiceLocator" class="com.landy.ioc_01.DefaultServiceLocator" ></bean>
    <!-- 通过指定非静态工厂对象和方法名来生产IoC信息   -->
    <bean id="clientServiceImplclientService" factory-bean="defaultServiceLocator" factory-method="createInstance"></bean>

4. 基于单个构造参数的组件依赖注入配置

4.1 准备组件类
public class UserDao {
}
public class UserService {
    public UserDao userDao;

    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }
}
4.2 编写配置文件
    <!-- 引用和被应用的组件必须在IoC容器中存在,否则会报错。   -->
    <!-- 1. 单个构造参数注入   -->
    <bean id="userDao" class="com.landy.ioc_02.UserDao " />
    <bean id="userService" class="com.landy.ioc_02.UserService">
        <!--  构造参数传值,DI的配置 value:直接属性值 ref:引用其他组件,输入组件id值     -->
        <constructor-arg  ref="userDao" />
    </bean>

5. 基于多个构造参数的组件依赖注入配置 

5.1 准备组件类
public class UserService {
    public UserDao userDao;
    private int age;
    private String name;
    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }

    public UserService(UserDao userDao, int age, String name) {
        this.userDao = userDao;
        this.age = age;
        this.name = name;
    }
}
5.2 编写配置文件

        三种方式,推荐使用第二种

    <!-- Spring IoC是一个高级容器,内部有缓存。 1, 先创建对象(IoC)2. 再进行属性赋值(DI)   -->
    <!-- 2. 多个构造参数注入   -->
    <bean id="userDao2" class="com.landy.ioc_02.UserDao " />
    <bean id="userService2" class="com.landy.ioc_02.UserService">
        <!--    按构造参数顺序填写值  value:直接赋值 ref:引用其他组件,值为组件id  -->
        <constructor-arg ref="userDao2"></constructor-arg>
        <constructor-arg value="18"></constructor-arg>
        <constructor-arg value="帅哥李"></constructor-arg>

    </bean>

    <bean id="userService2" class="com.landy.ioc_02.UserService">
        <!--    按构造参数名称填写值,不考虑顺序  填写name = "构造参数名称" 即可 -->
        <constructor-arg name="age" value="18"></constructor-arg>
        <constructor-arg name="name" value="帅哥李"></constructor-arg>
        <constructor-arg name="userDao" ref="userDao2"></constructor-arg>
    </bean>

    <bean id="userService2" class="com.landy.ioc_02.UserService">
        <!--    按构造参数Index填写值,从左到右,从0开始  -->
        <constructor-arg index="1" value="18"></constructor-arg>
        <constructor-arg index="2" value="帅哥李"></constructor-arg>
        <constructor-arg index="0" ref="userDao2"></constructor-arg>
    </bean>

6. 基于Setter方法的组件依赖注入配置  

6.1 准备组件类
public class MovieFinder {
}
public class SimpleMovieLister {
    private MovieFinder movieFinder;
    private String movieName;

    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

    public void setMovieName(String movieName) {
        this.movieName = movieName;
    }
}
6.2 编写配置文件
<!-- 除法Setter方法进行注入   -->
    <!--  需要注入的引用组件  -->
    <bean id="movieFinder" class="com.landy.ioc_02.MovieFinder" />

    <bean id="simpleMovieLister" class="com.landy.ioc_02.SimpleMovieLister">
        <!--   name:setter方法的去set和首字母小写值,调用set方法     -->
        <!--   ref:其他组件的id | value:直接属性值     -->
        <property name="movieName" value="复仇者联盟"/>
        <property name="movieFinder" ref="movieFinder"/>
    </bean>

7. IoC和DI配置完成后!创建IoC容器并使用

        声明IoC容器对象,读取配置文件,使配置文件中声明的组件类信息真正的进行实例化成Bean对象和形成Bean之间的引用关系。实例化组件Bean和引用关系的维护都是再IoC容器中实现的。

7.1. 创建IoC容器
    /**
     * 如何创建IoC容器并读取配置文件
     */
    public void creatIoc(){
        // 创建IoC容器
        // 创建合适的容器实现即可
        /*
            接口:
                BeanFactory
                    ApplicationContext
             实现类:
                ClassPathXmlApplicationContext:读取类路径下的XML的配置方式 classes
                FileSystemXmlApplicationContext:读取指定文件位置的XML配置
                AnnotationConfigApplicationContext:读取配置类的方式的IoC容器
                WebApplicationContext
         */

        // 方式1:直接创建容器并指定配置文件路径
        // String... 配置文件
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring_03.xml");
        // 方式2:先创建IoC容器对象,再指定配置文件路径,再刷新
        // 创建容器和指定路径分开
        ClassPathXmlApplicationContext applicationContext1 = new ClassPathXmlApplicationContext();
        applicationContext1.setConfigLocation("spring_03.xml");
        applicationContext1.refresh(); // 调用IoC和DI
    }
7.2 从IoC容器中获取组件实例
    /**
     * 如何再IoC容器中获取组件Bean
     */
    public void getBeanFromIoC(){
        // 1. 创建IoC容器
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring_03.xml");
        // 2. 读取IoC容器的组件
        // 方法1:根据BeanId获取:需要强转,不推荐
        SadComponent sadComponent = (SadComponent) applicationContext.getBean("sadComponent");
        // 方法2:根据BeanId,同时指定Bean类型 Class
        SadComponent sadComponent1 = applicationContext.getBean("sadComponent", SadComponent.class);
        // 方法3:直接根据类型获取,如果IoC容器存在多个通Class的Bean,会出现不唯一异常
        // IoC的配置一定是实现类,但是可以根据接口获取值!底层使用instanceof进行判断        
        SadComponent sadComponent2 = applicationContext.getBean(SadComponent.class);
    }

组件Bean:作用域和周期方法配置

周期方法:

        到了对应时间节点,主动被调用的方法。如Servlet的init初始化、destroy销毁等周期方法,被Tomcat调用。

组件类的周期方法:

        我们可以在组件类中定义方法,然后党IoC容器实例化和销毁组件对象的时候进行调用。

周期方法的声明:

        周期方法必须是Public、void、无参的。在类中声明即可

public class JavaBean {
    /**
     * 必须是Public,必须void,必须是无参数的
     * 初始化方法 -> 初始化业务逻辑
     */
    public void init() {
        System.out.println("JavaBean init");
    }

    /**
     * 必须是Public,必须void,必须是无参数的
     * 销毁方法
     */
    public void destroy() {
        System.out.println("JavaBean destroy");
    }
}

        配置文件中使用init-method和destory-method属性声明周期方法

<!-- init-method = "初始化方法名" destory-method = "销毁方法名"   -->
    <bean id="javaBean" class="com.landy.ioc_04.JavaBean" init-method="init" destroy-method="destroy" />
作用域: 

        IoC容器根据<bean/>标签的信息将组建转化为Spring内部的BeanDefinition对象,BeanDefinition对象内包含了标签的定义信息,如id,class等。SpringIoC容器可以根据BeanDefinition对象反射创建多个Bean对象实例,具体创建多少个Bean的实例对象,有Bean组件的作用域Scope属性指定。

作用域可选值:

singleton:IoC容器中的Bean对象始终为单实例。IoC容器初始化时创建对象。是Bean对象的默认值

prototype:IoC容器中的Bean对象有多个实例。IoC获取Bean时创建对象。

配置文件:
    <!-- 单例模式   -->
    <bean id="javaBean2" class="com.landy.ioc_04.JavaBean2" scope="singleton" />
    <!--  多例模式  -->
    <bean id="javaBean22" class="com.landy.ioc_04.JavaBean2" scope="prototype" />

FactoryBean接口:简化工厂模式的Bean组件配置

工厂类实现FactoryBean即可在配置文件中省略facotry-bean/factory-method等信息的配置

创建待实例的类
public class JavaBean3 {
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}
创建实例的工厂类:
// 1. 实现FactoryBean接口,指定返回值泛型
public class JavaBeanFactory implements FactoryBean<JavaBean3> {
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public JavaBean3 getObject() throws Exception {
        // 使用自己的方式实例化对象
        JavaBean3 javaBean3 = new JavaBean3();
        javaBean3.setName(name);
        return javaBean3;
    }

    @Override
    public Class<?> getObjectType() {
        return JavaBean3.class;
    }
}
配置文件:
<!--  id="getObject返回的对象标识" class="FactoryBean的标准化工厂类"  工厂对象本身的id为 & + FactoryBean的id-->
    <bean id="javaBean3" class="com.landy.ioc_05.JavaBeanFactory">
        <!--   工厂类内部赋值,是给工厂对象赋值,不是工厂模式实例化的对象的属性赋值     -->
        <!--   要想给工厂模式实例化的对象赋值,需要给工厂模式实例化的对象添加响应属性,先给工厂的属性赋值,再给工厂生产的对象赋值     -->
        <property name="name" value="landy"/>
    </bean>

上述便是XML配置IoC容器的基本内容~

二、基于注解配置方式组件管理

创建bean标签 -> 添加相关注解

常见注解:

@Component:用于描述Spring中的Bean,可用在任何层次(Service、Dao)。使用时只需将该注解标注在响应类上即可

@Repository:用于将数据访问层(Dao)层的类表示为Spring中的Bean,功能与@Component相同

@Service:用于将业务层(Service)层的类表示为Spring中的Bean,功能与@Component相同

@Controller:用于将控制层(如SpringMVC中的Controller),用于将控制层的类表示为Spring中的Bean,功能与@Component相同。

通过源码可知:四个注解没有本质区别,@Service、@Repository、@Controller三个注解只是在@Component注解的基础上起了三个新的名字,用于区分不同组件。

配置扫描包:

当注解注释完成后,需要配置扫描包。

    <!--  1. 普通配置包扫描  -->
    <!--  base-package:指定IoC容器去哪些包下查找注解类,可指定多个包,用逗号,分隔  -->
    <context:component-scan base-package="com.landy.ioc_01"/>
    <!-- 排除指定组件   -->
    <!--  type属性:指定根据什么来进行排除,annotation取值表示根据注解排除  -->
    <!--  expression属性:指定排除规则的表达式,对于注解来说指定全类名即可  -->
    <context:component-scan base-package="com.landy.ioc_01">
        <!--   排除Controller注解     -->
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>
    <!-- 指定包含注解   -->
    <!--  use-default-filters="false":表示不包含默认的过滤规则,默认为true  -->
    <context:component-scan base-package="com.landy.ioc_01" use-default-filters="false">
        <!--   只包含Controller注解     -->
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>
 IoC注解组件的默认Id为类首字母小写名,也可以声明value属性以重命名:@Component("renameName")

组件Bean:作用域和周期方法注解

周期方法声明:

周期方法要求:方法命名无要求,但是必须时Public权限修饰符、void无返回值且无形参

@PostConstruct:注解指定初始化方法

@PreDestroy:注解指定销毁方法

作用域配置:

@Scope(scopeName = ConfigurableBeanFactory.SCOPE_SINGLETON) 单例,默认

@Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE) 多例

Bean组件中的引用类型属性赋值:

前提:参与自动装配的组件(需要装配、被装配)必须都在IoC容器中

注解:@Autowired:在成员变量直接添加此注解即可

示例如下:

需要注入的Service类:

@Service
public class UserServiceImpl implements UserService{
    @Override
    public void show() {
        System.out.println("I like to show");
    }
}

Controller中使用注解注入:

@Controller
public class UserController {
    // 自动装配注解:DI
    // 1. IoC容器中查找复合类型的组件对象
    // 2. 赋值给当前属性
    @Autowired
    private UserService userService;
}

@Autowired注解实现原理:

 1. 根据所需组件类型到IoC容器中查找

2. 找到唯一的Bean -> 直接装配

3. 找不到匹配类型的Bean -> 装配失败

4. 匹配类型的Bean不止一个(一个接口有多个实现) -> 查找@Qualifier(value="idName")注解,根据@Qualifier注解指定的名称作为Bean的id进行匹配 / 根据属性名寻找

@Resource(name = "idName") = @Autowired + @Qualifier @Resource注解能够简化@Autowired和@Qualifier双注解的麻烦。但是需要通过xml坐标导入相关依赖。

<dependency>
    <groupId>jakarta.annotation</groupId>
    <artifactId>jakarta.annotation-api</artifactId>
    <version>2.1.1</version>
</dependency>

Bean组件中的基本类型属性赋值: 

两种方法:直接赋值 / 注解引用外部文件

外部文件:application.properties

handsome.name = Landy

IoC中声明引用:

<context:component-scan base-package="com.landy.ioc_04"/>
<context:property-placeholder location="classpath:application.properties"/>

类中注入,可添加默认值: 

@Component
public class JavaBean {
    // 1. 直接赋值
    // name = "Landy"
    // 2. 注解赋值:可读取外部配置文件
    // 冒号:后为默认值
    @Value("${handsome.name:admin}")
    private String name;
    private String userName;
}

三、基于配置类方式组件管理

配置类->替代XML配置文件

1. 创建config包,创建Configuration配置类
/**
 * java的配置类,代替XML配置文件
 *  1. 包扫描注解配置
 *  2. 引用外部配置文件
 *  3. 声明第三方依赖的bean组件
 * @Configuration:配置类注解
 *
 */
@ComponentScan(value = "com.landy.ioc_01")
@PropertySource(value = "classpath:application.properties")
@Configuration
public class JavaConfiguration {
}

@Configuration:包扫描注解(value="待扫描包名",...)

@PropertySource:引入外部配置文件("classpath:配置文件名")

@Configuration:配置类注解

2. 创建配置类的IoC容器:
// IoC容器实例化
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(JavaConfiguration.class);
3. 外部组件的声明 

通过方法声明:

方法的返回值类型 == bean组件的类型或者接口和父类

方法的名字 = bean id

方法体自定义实现过程即可

方法上需要添加@Bean注解,使配置类的方法创建的组件存到IoC容器

@ComponentScan(value = "com.landy.ioc_01")
@PropertySource(value = "classpath:application.properties")
@Configuration
public class JavaConfiguration {
    @Value("${landy.url}")
    private String url;
    @Value("${landy.driver}")
    private String driver;
    @Value("${landy.username}")
    private String username;
    @Value("${landy.password}")
    private String password;
    /**
     * 方法的返回值类型 == bean组件的类型或者接口和父类
     * 方法的名字 = bean id
     * 方法体自定义实现过程即可
     * 方法上需要添加@Bean注解,使配置类的方法创建的组件存到IoC容器
     * @return dataSource 需要声明的组件
     */
    @Bean
    public DataSource dataSource(){
        // 实现具体的实例化过程
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        dataSource.setDriverClassName(driver);
        return dataSource;
    }
}

如何修改Bean id?

@Bean(name="newName" / value = "newName")

Bean的周期方法如何指定?

1. @PostConstruct / @PreDestory注解

2. @Bean(initMethod="methodName", destoryMethod="methodName")

Bean的作用域?

@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON/PROTOTYPE)

如何引用其他组件?如JdbcTemplate需要DataSource

1. 直接调用@Bean注释的方法(不推荐!)

@Bean
    public JdbcTemplate jdbcTEmplate(){
        return new JdbcTemplate(dataSource());
    }

2. 形参列表声明需要的组件类型

@Bean
public JdbcTemplate jdbcTEmplate(DataSource dataSource){
    return new JdbcTemplate(dataSource);
}

 以形参形式注入,必须有对应类型组件于IoC中,如果没有抛出异常!

如果有多个同类型组件,使用形参名称==对应Bean id即可

4. @Import拓展

将父配置类加载给子配置类,最后只需要加载一个配置类即可。

@Import(value = ConfigurationFatherA.class, ConfigurationFatherB.class)

以上便是Spring IoC容器管理配置的三种方式啦~

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值