吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1472|回复: 5
收起左侧

[学习记录] [Spring学习记录]学习到基于XML配置的SpringIoC阶段的学习笔记

  [复制链接]
xiaotian1339 发表于 2022-11-29 22:30
本帖最后由 xiaotian1339 于 2022-11-29 22:32 编辑

纯小白的学习笔记,学习的还比较不到位不全面,欢迎大佬指正错误

基于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="userDao" class="com.demo.dao.impl.UserDaoImpl"></bean>

    <!--    class:Beam对象的全限定名称-->
    <!--    id属性:bean对象的唯一标识,会转为默认的name,若空则name变为该类全限定名称-->
    <!--    init-method属性设置的方法在构造并且注入结束之后调用,若类还实现了InitializingBean接口,则在该接口中afterPropertiesSet方法之后执行-->
    <!--    InitializingBean 接口中 afterPropertiesSet 方法在构造并注入结束之后调用 -->
    <!--    destroy-method属性设置的方法,在显式调用容器的close方法之后调用,若直接强制关闭容器则不调用,例如直接结束进程-->
    <!--    scope属性有两个值:
                singleton(默认):在ApplicationContext容器new之后直接创建单例,并存储在单例池中
                prototype: 原型方法,在ApplicationContext容器new之后不会主动创建bean对象,每调用getBean方法时创建一个新的实例对象,不会存在单例池中
            -->
    <!--    lazy-init属性[true,false]:是否懒加载,true则在调用getBean方法是再new对象。::只在Spring容器中生效的属性,BeanFactory容器不生效::-->
    <!--    name属性:别名,可以取多个名字,底层是把名字存在一个map中,指向被取代的id名,若无id,则容器的名字则为name属性的第一个值-->
    <bean id="userService" class="com.demo.service.impl.UserServiceImpl" init-method="initMethod"
          destroy-method="destroyMethod">
        <!--        property:依赖注入  name属性为该bean对象的setXxx方法名字中的xxx,首字母小写;ref值为要注入的bean对象-->
        <property name="userDao" ref="userDao"></property>
        <!--        constructor-arg表示调用其有参构造  name表示参数名,value表示值-->
        <!--        constructor-arg只要是构造时需要的参都可以传,不只构造函数-->
        <constructor-arg name="var1" value="tc"></constructor-arg>
        <constructor-arg name="var2" value="7"></constructor-arg>
    </bean>

    <!--    配置静态工厂拿到非工厂对应实例-->
    <!--    class为工厂全限定名称-->
    <!--    factory-method为return实例的静态方法-->
    <!--    如果方法里面有参数可用constructor-arg标签定义-->
    <bean id="userDao1" class="com.demo.factory.MyStaticBeanFactory" factory-method="getUserDao"></bean>

    <!--    配置实例工厂-->
    <!--    第一步拿到工厂实例-->
    <bean id="entityBeanFactory" class="com.demo.factory.MyEntityBeanFactory"></bean>
    <!--    第二步,通过实例工厂拿到所需的实例对象-->
    <!--    如果方法里面有参数可用constructor-arg标签定义-->
    <bean id="userDao2" factory-bean="entityBeanFactory" factory-method="getUserDao">
        <!--        可以用单标签,避免idea标签空体的警告-->
        <constructor-arg name="name" value="arg1"/>
    </bean>

    <!--    实现FactoryBean规范延迟实例化Bean-->
    <bean id="userDao3" class="com.demo.factory.MyFactoryBeanFactory">
        <!--  实际上,这种方式声明的
              单例池中保存的是MyFactoryBeanFactory对象,只有调用getBean方法时,才会实例化并保存在FactoryBeanObjectCache中-->
    </bean>

<!--    注入List set Map 等-->
    <bean id="deptService" class="com.demo.service.impl.DeptServiceImpl">
<!--        基本数据类型List-->
        <property name="stringList">
<!--            因为是List所以用list标签包裹-->
            <list>
<!--                注入的项目 基础数据类型-->
                <value>aaa</value>
                <value>bbb</value>
                <value>ccc</value>
            </list>
        </property>
<!--        引用数据类型List-->
        <property name="userDaoList">
            <list>
<!--                拿到的是Spring容器中的单例-->
<!--                也可以用bean标签直接配
<bean id="userDao" class="com.demo.dao.impl.UserDaoImpl"></bean>
-->
                <ref bean="userDao"></ref>
                <ref bean="userDao1"></ref>
                <ref bean="userDao2"></ref>
                <ref bean="userDao2"></ref>
            </list>
        </property>
<!--        Set与List注入方式相同 只是list标签变成set标签-->

<!--        map-->
        <property name="map">
            <map>
<!--                若为基础数据类型就不用带-ref  引用数据类型就使用-ref-->
                <entry key="a" value-ref="userDao"></entry>
                <entry key="b" value-ref="userDao1"></entry>
                <entry key="c" value-ref="userDao2"></entry>
            </map>
        </property>

<!--        properties 其实就相当于键值对都为String的Map-->
        <property name="properties">
<!--            和Map一样不能有相同的Key 相同的话应该会取最后一个值-->
            <props>
                <prop key="a">aaa</prop>
                <prop key="b">bbb</prop>
                <prop key="c">ccc</prop>
                <prop key="a">ddd</prop>
            </props>
        </property>

    </bean>

<!--    上面是手动装配-->
<!--    介绍自动装配 -> byName 根据Bean中setXxx方法的Xxx找配置好的且id/name=xxx的bean实例注入-->
<!--    ......... -> byType 根据Bean中set方法的入参类型匹配到配置好的bean注入.::注意,使用byType时配置文件中匹配到的Bean只能有且仅有一个,否则会报错::-->

<!--    本例:byName中会找到AutoWireServiceImpl中setDeptService方法,找到set后面的deptService(名称匹配)的bean并注入-->
    <bean id="autoWireService" class="com.demo.service.impl.AutoWireServiceImpl" autowire="byName"></bean>
<!--    本例:byType中会找到AutoWireServiceImpl中setDeptService方法,找到与传入参数类型相同的Bean并注入,该类型的bean应保证有且只有1个-->
    <bean id="autoWireService2" class="com.demo.service.impl.AutoWireServiceImpl" autowire="byType"></bean>

</beans>

拿到Bean的三种方式

​        1.通过bean的id来获取

​                        所拿到的类型时Object,需要强转

UserDao userDao = (UserDao) context.getBean("userDao");

​        2.通过bean的类型来获取

​                        这种方式要求Spring容器中有且仅有一种该类型的Bean,返回的即为对应类型

UserDao userDao = context.getBean(UserDao.class);

​        3.通过bean的id和类型来获取

​                        这种方式无需强制类型转换,也解决了对于多个对象的同一种Bean获取会报错的问题。

UserDao date = context.getBean("userDao", UserDao.class);

生成Bean的三种方式

配置文件中也有测试,不过还是单独拿出来在写一写,加深一下印象,打个标题以后也方便找
1.通过bean的构造函数获取**

<bean id="userDao" class="com.demo.dao.impl.UserDaoImpl"/>

2.使用静态工厂创建bean

假设有一个静态工厂

public class UserDaoFactory {
     public static UserDao getUserDao() {
          return new UserDaoImpl();
     }
}

则,xml中

<bean id="userDao" class="com.demo.factory.UserDaoFactory" factory-method="getUser" init-method="init"/>

3.使用实例工厂创建bean

假设有一个实例工厂

public class UserDaoInstanceFactory {
     public UserDao getUserDao() {
          return new UserDaoImpl();
     }
}

则xml

<bean id="userDaoInstanceFactory" class="com.demo.factory.UserDaoInstanceFactory"/>
<bean id="userDao" factory-bean="userDaoInstanceFactory" factory-method="getUserDao"/>

注意:id为唯一标识,不能相同;可以使用beans的profile划分工作区


后处理器

BeanFactoryPostProcessor

BeanDefinitionMap填充完毕后,实例Bean前执行接口方法

1.BeanFactoryPostProcessor接口
void postProcessBeanFactory(ConfigurableListableBeanFactory var1) throws BeansException;

例子:

  1. 更改BeanDefinitionMap中Bean的配置信息
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
    BeanDefinition userDaoBeanDefinition = configurableListableBeanFactory.getBeanDefinition("userDao");
    userDaoBeanDefinition.setBeanClassName("com.demo.service.impl.UserServiceImpl");
}

以上例子更改userDao的class为UserService,执行实例化后,原为UserDaoImpl的userDao会被实例化为UserServiceImpl   id名字不变

  1. 注册未在配置文件中配置的Bean
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
    // 1.注册BeanDefinition
    BeanDefinition beanDefinition = new RootBeanDefinition();
    beanDefinition.setBeanClassName("com.demo.dao.impl.UserDaoImpl");
    // 2.强转成DefaultListableBeanFactory
    DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) configurableListableBeanFactory;
    // 3.利用DefaultListableBeanFactory将Definition注册到map中
    defaultListableBeanFactory.registerBeanDefinition("userDao",beanDefinition);
}

2.BeanDefinitionRegistryPostProcessor接口
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
    void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry var1) throws BeansException;
}

针对BeanFactoryPostProcessor接口例子2的更简单的实现

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
        BeanDefinition beanDefinition = new RootBeanDefinition();
        beanDefinition.setBeanClassName("com.demo.dao.impl.UserDaoImpl");
        beanDefinitionRegistry.registerBeanDefinition("userDao",beanDefinition);
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {    }

BeanPostProcessor

Bean实例化完毕后及依赖注入完成后执行接口方法

BeanPostProcessor接口
public interface BeanPostProcessor {
    @Nullable
    default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Nullable
    default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
}

postProcessBeforeInitialization: 在调用init-method ( InitializingBean接口方法 [若有] ) 之前调用

postProcessAfterInitialization:  在调用init-method  ( InitializingBean接口方法 [若有] )之后调用

例子  动态代{过}{滤}理增强Bean功能

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        UserDao o = (UserDao) Proxy.newProxyInstance(bean.getClass().getClassLoader(),
                bean.getClass().getInterfaces(),
                (proxy, method, args) -> {
                    System.out.println("执行开始:" + new Date().getTime());
                    Object invoke = method.invoke(bean, args);
                    System.out.println("执行结束:" + new Date().getTime());
                    return invoke;
                });
        return o;
    }

对所有原有方法调用前后均在控制台输出一下时间


整合第三方框架

这里以Mybatis为例

com.demo.mapper.UserMapper.java

public interface UserMapper {
    List<User> findAll();
}

com.demo.pojo.User.java

public class User {
    private Integer id;
    private String username;
    private String password;
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }

com.demo.service.impl.UserServiceImpl.java

public class UserServiceImpl implements UserService {
    private UserMapper userMapper;

    public void setUserMapper(UserMapper userMapper) {
        this.userMapper = userMapper;
    }

    public void printUser(){
        List<User> all = userMapper.findAll();
        for (User user : all) {
            System.out.println(user);
        }
    }

UserService接口只有一个printUser方法

资源路径下

com.demo.mapper.UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.demo.mapper.UserMapper">
    <select id="findAll" resultType="com.demo.pojo.User"><![CDATA[
        select * from user where id < 10
    ]]></select>
</mapper>

对于Spring的XML配置文件只需配置以下的基础信息(以druid为例)

 <bean id="userService" class="com.demo.service.impl.UserServiceImpl">
            <property name="userMapper" ref="userMapper"/>
        </bean>

        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
            <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
            <property name="url" value="jdbc:mysql://localhost:1234/xxx"/>
            <property name="username" value="xxxx"/>
            <property name="password" value="xxxx"/>
        </bean>

        <bean class="org.mybatis.spring.SqlSessionFactoryBean">
            <property name="dataSource" ref="dataSource"/>
        </bean>
        <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <property name="basePackage" value="com.demo.mapper"/>
        </bean>

在测试类中拿到UserService后即可打印出对应sql结果


免费评分

参与人数 2吾爱币 +2 热心值 +2 收起 理由
shizi1521 + 1 + 1 用心讨论,共获提升!
我是白小白 + 1 + 1 用心讨论,共获提升!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

L133 发表于 2022-11-30 00:10
可以很强
lfordch 发表于 2022-11-30 04:07
Sorryks 发表于 2022-11-30 07:15
zmp520 发表于 2022-11-30 08:13
膜拜一下大佬,
yzjtxwd 发表于 2022-11-30 09:27
学习一下
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-25 04:04

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表