②Spring-FactoryBean

目录

        1.FactoryBean

        2.Bean 作用域和生命周期

        2.1 Bean 作用域

        2.2 Bean 生命周期

        2.3 Bean 后置处理器

        3.注解方式

        3.1 什么是注解

        3.2 创建对象

        3.3 组件扫描配置

        设置扫描

        设置不扫描

        4.属性注入

        4.1 @Autowired

        4.2 @Qualifier

        4.3 @Resource

        4.4 @Value

        4.5 完全注解开发


1.FactoryBean

Spring 有两种类型 Bean,一种是普通 Bean,另外一种是工厂 Bean(FactoryBean)

  • 普通 Bean:在配置文件中定义的 Bean 类型就是返回类型

  • 工厂 Bean:在配置文件中定义的 Bean 类型可以和返回类型不一致

上述的例子都是普通 Bean 的类型,那么工厂 Bean 该怎么实现呢

1)创建类,实现 FactoryBean 接口,使其作为一个工厂 Bean

2)实现接口中的方法,在实现方法中定义返回的 Bean 类型

public class MyFactoryBean implements FactoryBean<Course> {
    @Override
    public Course getObject() throws Exception {
        Course course = new Course();
        course.setCname("CourseName");
        return course;
    }
​
    @Override
    public Class<?> getObjectType() {
        return null;
    }
}

 

3)在 Spring 配置文件中进行配置

<bean id="myFactoryBean" class="com.zking.spring.factorybean.MyBean"></bean>

由于是 FactoryBean,所以再通过上下文获取时,需要使用实现 FactoryBean 时传入的泛型类型进行接收

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean5.xml");
Course course = applicationContext.getBean("myFactoryBean", Course.class);

如果仍然使用配置文件中定义的 Bean 类型,则会报错

org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'myBean' is expected to be of type 'com.zking.spring.factorybean.MyBean' but was actually of type 'com.zking.spring.collectiontype.Course'

2.Bean 作用域和生命周期

2.1 Bean 作用域

在 Spring 里面,可以设置创建 Bean 的实例是单实例还是多实例,默认情况下是单实例

<bean id="book" class="com.zking.spring.collectiontype.Book"></bean>

测试

ApplicationContext context = new ClassPathXmlApplicationContext("bean6.xml");
Book book1 = context.getBean("book", Book.class);
Book book2 = context.getBean("book", Book.class);
System.out.println(book1 == book2); // true 表示是同一个对象,证明默认情况下是单实例

如何设置单实例多实例?

在 Spring 配置文件中 bean 标签里scope属性用于设置单实例还是多实例

  • 1)singleton,单实例,默认情况下不写也是它

  • 2)prototype,多实例

  • <bean id="book2" class="com.zking.spring.collectiontype.Book" scope="prototype"></bean>

测试

Book book3 = context.getBean("book2", Book.class);
Book book4 = context.getBean("book2", Book.class);
System.out.println(book3 == book4); // false 表示不是同一个对象,证明scope为prototype时是多实例

singletonprototype的区别

singletonprototype除了单实例和多实例的差别之外,还有以下区别

  • 设置scope值是singleton时,加载 Spring 配置文件时就会创建单实例对象

  • 设置scope值是prototype时,加载 Spring 配置文件时不会创建对象,而是在调用getBean方法时创建多实例对象

 scope的其他值

scope的属性值除了singletonprototype之外,其实还有一些属性值,如

  • request,每个request创建一个新的 bean

  • session,同一session中的 bean 是一样的

不过这两个属性值使用非常少,了解即可

2.2 Bean 生命周期

生命周期:从对象创建到对象销毁的过程

Bean 生命周期

  1. 通过构造器创建 Bean 实例(无参构造)

  2. 为 Bean 属性设置值和对其他 Bean 引用(调用 setter 方法)

  3. 调用 Bean 的初始化方法(需要进行配置初始化方法)

  4. Bean 就可以使用了(对象获取到了)

  5. 当容器关闭时,调用 Bean 的销毁方法(需要进行配置销毁方法)

代码演示

public class Orders {
​
    //无参数构造
    public Orders() {
        System.out.println("第一步 执行无参数构造创建bean实例");
    }
​
    private String oname;
    public void setOname(String oname) {
        this.oname = oname;
        System.out.println("第二步 调用set方法设置属性值");
    }
​
    //创建执行的初始化的方法
    public void initMethod() {
        System.out.println("第三步 执行初始化的方法");
    }
​
    //创建执行的销毁的方法
    public void destroyMethod() {
        System.out.println("第五步 执行销毁的方法");
    }
}

Spring 配置文件中的配置、

<bean id="orders" class="com.zking.spring.bean.Orders" init-method="initMethod"
      destroy-method="destroyMethod">
    <property name="oname" value="手机"></property>
</bean>

测试

ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean7.xml");
Orders orders = context.getBean("orders", Orders.class);
System.out.println("Step4.获取创建Bean实例对象.");
System.out.println(orders);
// 手动销毁Bean实例
context.close();

执行结果

第一步 执行无参数构造创建bean实例
第二步 调用set方法设置属性值
第三步 执行初始化的方法
第四步 获取创建bean实例对象
com.zking.spring.bean.Orders@c81cdd1
第五步 执行销毁的方法

Spring 中 Bean 更加完整的生命周期其实不止上述 5 步,另外还有 2 步操作叫做 Bean 的后置处理器

2.3 Bean 后置处理器

加上 Bean 后置处理器,Bean 生命周期如下

  1. 通过构造器创建 Bean 实例(无参构造)

  2. 为 Bean 属性设置值和对其他 Bean 引用(调用 setter 方法)

  3. 把 Bean 的实例传递给 Bean 后置处理器的postProcessBeforeInitialization方法

  4. 调用 Bean 的初始化方法(需要进行配置初始化方法)

  5. 把 Bean 的实例传递给 Bean 后置处理器的postProcessAfterInitialization方法

  6. Bean 就可以使用了(对象获取到了)

  7. 当容器关闭时,调用 Bean 的销毁方法(需要进行配置销毁方法)

代码演示

1)创建类,实现接口BeanPostProcessor,创建后置处理器

public class MyBeanPost implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("在初始化之前执行的方法");
        return bean;
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("在初始化之后执行的方法");
        return bean;
    }
}

2)Spring 配置文件中配置后置处理器

<!--配置后置处理器,会为当前配置文件中所有bean添加后置处理器-->
<bean id="myBeanPost" class="com.zking.spring.bean.MyBeanPost"></bean>

执行结果

第一步 执行无参数构造创建bean实例
第二步 调用set方法设置属性值
在初始化之前执行的方法
第三步 执行初始化的方法
在初始化之后执行的方法
第四步 获取创建bean实例对象
com.zking.spring.bean.Orders@289d1c02
第五步 执行销毁的方法

3.注解方式

3.1 什么是注解

  • 注解是一种代码特殊标记,格式:@注解名称(属性名称=属性值,属性名称=属性值...)

  • 注解作用:在类上面,方法上面,属性上面

  • 注解目的:简化 XML 配置

3.2 创建对象

  • @Component

  • @Service

  • @Controller

  • @Repository

上面四个注解功能是一样的,都可以用来创建 Bean 实例

1)引入依赖

spring-aop.xxx.jar

2)开启组件扫描

<?xml version="1.0" encoding="UTF-8"?>
<!--引入context名称空间-->
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    <!--开启组件扫描:多个包用逗号隔开-->
    <context:component-scan base-package="com.zking.spring.dao,com.zking.spring.service"></context:component-scan>
​
</beans>

3)创建类,在类上添加创建对象注解

/**
 * value可省略,默认值为类名首字母小写
 */
@Component(value = "userService")
public class UserService {
    public void add(){
        System.out.println("UserService add...");
    }
}

3.3 组件扫描配置

设置扫描

  • use-default-filters表示现在不使用默认filter,自己配置filter

  • include-filter设置扫描哪些内容

<context:component-scan
            base-package="com.zking.spring" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

设置不扫描

  • 配置扫描包下所有内容

  • exclude-filter设置不扫描哪些内容

  • <context:component-scan
                base-package="com.zking.spring">
            <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
        </context:component-scan>
 

4.属性注入

  • @Autowired根据属性类型进行自动装配

  • @Qualifier根据属性名称进行注入,需要和@Autowired一起使用

  • @Resource可以根据类型和名称注入

  • @Value根据普通类型注入

4.1 @Autowired

1)创建 Service 和 Dao 对象,在 Service 和 Dao 类上添加创建对象注解

public interface UserDao {
    void add();
}
@Repository
public class UserDaoImpl implements UserDao{
    @Override
    public void add() {
        System.out.println("UserDaoImpl add...");
    }
}
@Service
public class UserService {
    public void add() {
        System.out.println("UserService add...");
    }
}

2)在 Service 类中添加 Dao 类型属性,在属性上面使用注解注入 Dao 对象

@Service
public class UserService {
​
    @Autowired
    private UserDao userDao;
​
    public void add() {
        System.out.println("UserService add...");
        userDao.add();
    }
}

因为@Autowired是根据属性类型进行注入的,如果 UserDao 的实现类不止一个,比如新增一个 UserDaoImpl2 类

@Repository
public class UserDaoImpl2 implements UserDao {
    @Override
    public void add() {
        System.out.println("UserDaoImpl2 add...");
    }
}

那么此时测试程序就会报错

Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userService': Unsatisfied dependency expressed through field 'userDao'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.zking.spring.s11_annotation.dao.UserDao' available: expected single matching bean but found 2: userDaoImpl,userDaoImpl2
...
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.zking.spring.s11_annotation.dao.UserDao' available: expected single matching bean but found 2: userDaoImpl,userDaoImpl2
...

大概意思就是说,主程序抛出了一个UnsatisfiedDependencyException不满足依赖异常,嵌套异常是NoUniqueBeanDefinitionExceptionBean定义不唯一异常,预期匹配单个 Bean 但是找到了两个 Bean

此时想要指定装配某一个实现类,就需要用到@Qualifier注解

4.2 @Qualifier

书接上回,如果我们想要从多个实现类中装配具体某一个实现类,可以这么写

@Autowired
@Qualifier(value = "userDaoImpl")
private UserDao userDao;

其中value值为具体的实现类上配置的注解中value

@Repository
public class UserDaoImpl implements UserDao{
    @Override
    public void add() {
        System.out.println("UserDaoImpl add...");
    }
}
@Repository
public class UserDaoImpl2 implements UserDao {
    @Override
    public void add() {
        System.out.println("UserDaoImpl2 add...");
    }
}

由于上述例子中,我们没有对@Repository配置相应的value,所以默认为首字母小写的类名

如果想使用 UserDaoImpl2 类,则

@Autowired
@Qualifier(value = "userDaoImpl2")
private UserDao userDao;

如果指定名称有误,即不存在名称为value对应的类,则会报NoSuchBeanDefinitionException异常,即找不到对应类

Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userService': Unsatisfied dependency expressed through field 'userDao'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.zking.spring.s11_annotation.dao.UserDao' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value=userDaoImpl1)}
...
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.zking.spring.s11_annotation.dao.UserDao' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value=userDaoImpl1)}

4.3 @Resource

根据类型注入

@Resource
private UserDao userDao;

根据名称注入

@Resource(name = "userDaoImpl")
private UserDao userDao;

需要注意的是@Resource注解所在包为javax.annotation即 Java 扩展包,所以 Spring 官方不建议使用该注解而推崇@Autowired@Qualifier注解

4.4 @Value

上述注解都是对对象类型的属性进行注入,如果想要装配普通类型属性,如基本数据类型及其包装类等,则可以需要使用@Value注解;

@Value(value = "${user.name}")
private String name;
@Value(value = "100")
private Integer age;
@Value(value = "200.0d")
private Double length;
@Value(value = "true")
private boolean isOk;
@Value(value = "0,a,3,6,test")
private String[] arrs;

@Value(value = "${user.name}"):需要加载外部属性资源文件

4.5 完全注解开发

创建配置类,替代 XML 配置文件

//标注当前类为配置类
@Configuration
//开启组件扫描
@ComponentScan({"com.zking.spring"})
//引入外部属性文件
@PropertySource({"classpath:config.properties"})
public class SpringConfig {
}

                

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/755699.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

阿里云服务器数据库迁云: 数据从传统到云端的安全之旅(WordPress个人博客实战教学)

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 文章目录 一、 开始实战1.2创建实验资源1.3重置云服务器ECS的登录密码&#xff08;请记住密码&#xff09;1.4 设置安全组端口1…

武汉星起航:跨境热销新趋势,亚马逊美国站与欧洲站选品大赏

亚马逊作为全球领先的电商平台&#xff0c;其美国站和欧洲站一直是全球卖家争相入驻的热门站点。这两个站点不仅拥有庞大的消费群体和完善的物流体系&#xff0c;更以其独特的选品策略吸引了众多消费者的目光。武汉星起航将深入剖析亚马逊美国站和欧洲站当前热销的选品&#xf…

【Qt】之【Bug】大量出现“未定义的标识符”问题

背景 构建时出现大量错误 原因 中文注释问题 解决 方法1. 报错代码附近的中文注释全部删掉。。。 方法2. 报错的文件添加 // Chinese word comment solution #pragma execution_character_set("utf-8")

爱奇艺 Opal 机器学习平台:特征中心建设实践

01 综述 Opal 是爱奇艺大数据团队研发的一站式机器学习平台&#xff0c;旨在提升特征迭代、模型训练效率&#xff0c;帮助业务提高收益。整个平台覆盖了机器学习生命周期中特征生产、样本构建、模型探索、模型训练、模型部署等在内的多个关键环节。其中特征作为模型训练的基石…

ZYNQ MPSOC浅说

1 MPSOC PL端 Zynq UltraScale MPSoC PL 部分等价于 FPGA。简化的 FPGA 基本结构由 6 部分组成&#xff0c;分别为可编程输入/输出单元、基本可编程逻辑单元、嵌入式块RAM、丰富的布线资源、底层嵌入功能单元和内嵌专用硬核等。 2 MPSOC PS端 MPSoC 实际上是一个以处理器为…

Quartz定时任务组件

官网&#xff1a;http://www.quartz-scheduler.org/ 1&#xff09;job - 任务 - 你要做什么事&#xff1f; 2&#xff09;Trigger - 触发器 - 做什么事&#xff0c;什么时候触发&#xff0c;可以传入任务 3&#xff09;Scheduler - 任务调度 - 可以传入多个触发器进行任务调…

软件测试之接口测试(Postman/Jmeter)

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 一、什么是接口测试 通常做的接口测试指的是系统对外的接口&#xff0c;比如你需要从别的系统来…

动手学深度学习(Pytorch版)代码实践 -卷积神经网络-29残差网络ResNet

29残差网络ResNet import torch from torch import nn from torch.nn import functional as F import liliPytorch as lp import matplotlib.pyplot as plt# 定义一个继承自nn.Module的残差块类 class Residual(nn.Module):def __init__(self, input_channels, num_chan…

AI副业赚钱攻略:掌握数字时代的机会

前言 最近国产大模型纷纷上线&#xff0c;飞入寻常百姓家。AI副业正成为许多人寻找额外收入的途径。无论您是想提高家庭收入还是寻求职业发展&#xff0c;这里有一个变现&#xff0c;帮助您掌握AI兼职副业的机会。 1. 了解AI的基础知识 在开始之前&#xff0c;了解AI的基础…

【笔记】Spring Cloud Gateway 实现 gRPC 代理

Spring Cloud Gateway 在 3.1.x 版本中增加了针对 gRPC 的网关代理功能支持,本片文章描述一下如何实现相关支持.本文主要基于 Spring Cloud Gateway 的 官方文档 进行一个实践练习。有兴趣的可以翻看官方文档。 由于 Grpc 是基于 HTTP2 协议进行传输的&#xff0c;因此 Srping …

zabbix监控进阶:如何分时段设置不同告警阈值(多阈值告警)

作者 乐维社区&#xff08;forum.lwops.cn&#xff09;乐乐 在生产环境中&#xff0c;企业的业务系统状态并不是一成不变的。在业务高峰时段&#xff0c;如节假日、促销活动或特定时间段&#xff0c;系统负载和用户访问量会大幅增加&#xff0c;此时可能需要设置更高的告警阈值…

vscode 使用正则将/deep/ 替换成 :deep()

在VSCODE编辑器的SEARCH中按上图书写即可&#xff0c;正则表达式如下&#xff1a;(\/deep\/)(.*?)(?\{) 替换操作如下&#xff1a;:deep($2) 如果有用,号隔开的用&#xff1a;(\/deep\/)(.*?)(?,)替换操作如下&#xff1a;:deep($2) 即可实现快速替换所有/deep/写法; 同理…

Cyuyanzhong的内存函数

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、memcpy函数的使用与模拟实现二、memmove函数的使用和模拟实现三、memset函数与memcmp函数的使用&#xff08;一&#xff09;、memset函数&#xff08;内存块…

一文速览Google的Gemma:从gemma1到gemma2

前言 如此文《七月论文审稿GPT第3.2版和第3.5版&#xff1a;通过paper-review数据集分别微调Mistral、gemma》所讲 Google作为曾经的AI老大&#xff0c;我司自然紧密关注&#xff0c;所以当Google总算开源了一个gemma 7b&#xff0c;作为有技术追求、技术信仰的我司&#xff0…

大模型ReAct:思考与工具协同完成复杂任务推理

ReAct: Synergizing Reasoning and Acting in Language Models Github&#xff1a;https://github.com/ysymyth/ReAct 一、动机 人类的认知通常具备一定的自我调节&#xff08;self-regulation&#xff09;和策略制定&#xff08;strategization&#xff09;的能力&#xff0…

福昕阅读器再打开PDF文件时,总是单页显示,如何设置打开后就自动显示单页连续的模式呢

希望默认进入连续模式 设置方法 参考链接 如何设置使福昕阅读器每次启动时不是阅读模式 每次启动后都要退出阅读模式 麻烦_百度知道 (baidu.com)https://zhidao.baidu.com/question/346796551.html#:~:text%E5%9C%A8%E3%80%90%E5%B7%A5%E5%85%B7%E3%80%91%E9%87%8C%E6%9C%89%E…

Springboot下使用Redis管道(pipeline)进行批量操作

之前有业务场景需要批量插入数据到Redis中&#xff0c;做的过程中也有一些感悟&#xff0c;因此记录下来&#xff0c;以防忘记。下面的内容会涉及到 分别使用for、管道处理批量操作&#xff0c;比较其所花费时间。 分别使用RedisCallback、SessionCallback进行Redis pipeline …

从零开始学Spring Boot系列-集成Spring Security实现用户认证与授权

在Web应用程序中&#xff0c;安全性是一个至关重要的方面。Spring Security是Spring框架的一个子项目&#xff0c;用于提供安全访问控制的功能。通过集成Spring Security&#xff0c;我们可以轻松实现用户认证、授权、加密、会话管理等安全功能。本篇文章将指导大家从零开始&am…

昇思25天学习打卡营第11天|基于MindSpore通过GPT实现情感分类

学AI还能赢奖品&#xff1f;每天30分钟&#xff0c;25天打通AI任督二脉 (qq.com) 基于MindSpore通过GPT实现情感分类 %%capture captured_output # 实验环境已经预装了mindspore2.2.14&#xff0c;如需更换mindspore版本&#xff0c;可更改下面mindspore的版本号 !pip uninsta…

Mysql常用SQL:日期转换成周_DAYOFWEEK(date)

有时候需要将查询出来的日期转换成周几&#xff0c;Mysql本身语法就是支持这种转换的&#xff0c;就是DAYOFWEEK()函数 语法格式&#xff1a;DAYOFWEEK(date) &#xff08;date&#xff1a;可以是指定的具体日期&#xff08; 如2024-06-29 &#xff09;&#xff0c;也可以是日期…