自定义作用域

  1. spring容器自带的有2种作用域,分别是singleton和prototype;还有3种分别是spring web容器
    环境中才支持的request、session、application
  2. singleton是spring容器默认的作用域,一个spring容器中同名的bean实例只有一个,多次获取得
    到的是同一个bean;单例的bean需要考虑线程安全问题
  3. prototype是多例的,每次从容器中获取同名的bean,都会重新创建一个;多例bean使用的时候
    需要考虑创建bean对性能的影响
  4. 一个应用中可以有多个spring容器
  5. 自定义scope 3个步骤,实现Scope接口,将实现类注册到spring容器,使用自定义的sope
    我们来看一下这个接口定义
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.lang.Nullable;
public interface Scope {/**
* 返回当前作用域中name对应的bean对象
* name:需要检索的bean的名称
* objectFactory:如果name对应的bean在当前作用域中没有找到,那么可以调用这个
ObjectFactory来创建这个对象
**/
Object get(String name, ObjectFactory<?> objectFactory);
/**
* 将name对应的bean从当前作用域中移除
**/
@Nullable
Object remove(String name);
/**
* 用于注册销毁回调,如果想要销毁相应的对象,则由Spring容器注册相应的销毁回调,而由自定义作
用域选择是不是要销毁相应的对象
*/
void registerDestructionCallback(String name, Runnable callback);
/**
* 用于解析相应的上下文数据,比如request作用域将返回request中的属性。
*/
@Nullable
Object resolveContextualObject(String key);
/**
* 作用域的会话标识,比如session作用域将是sessionId
*/
@Nullable
String getConversationId();
}

将实现类注册到spring容器需要调用org.springframework.beans.factory.config.ConfigurableBeanFactory#registerScope的方
法,看一下这个方法的声明

依赖注入之手动注入

通常情况下,系统中类和类之间是有依赖关系的,如果一个类对外提供的功能需要通过调用其他类的方法来实现的时候,说明这两个类之间存在依赖关系
spring容器内部都提供了支持,这个在spirng中将被依赖的对象设置到依赖的对象中,叫做依赖注入。
spring中依赖注入主要分为手动注入和自动注入,手动注入需要我们明确配置需要注入的对象。

  • 通过构造器注入
    构造器的参数就是被依赖的对象,构造器注入又分为3种注入方式:
    根据构造器参数索引注入
    根据构造器参数类型注入
    根据构造器参数名称注入

根据构造器参数索引(位置)注入

用法

UserController userController = new UserController();
userController.setService(userService);
//然后就可以使用userController对象了
<bean id="diByConstructorParamIndex"
class="com.javacode2018.lesson001.demo5.UserModel">
<constructor-arg index="0" value="xx"/>
<constructor-arg index="1" value="上海市"/>
</bean>

constructor-arg用户指定构造器的参数
index:构造器参数的位置,从0开始
value:构造器参数的值,value只能用来给简单的类型设置值,value对应的属性类型只能为byte,int,long,float,double,boolean,Byte,Long,Float,Double,枚举,spring容器内部注入的时候会将value的值转换为对应的类型。

UserModel.java

public class UserModel {private String name;
private int age;
//描述信息
private String desc;
public UserModel() {}
public UserModel(String name, String desc) {this.name = name;
this.desc = desc;
}
public UserModel(String name, int age, String desc) {this.name = name;
this.age = age;
this.desc = desc;
}
@Override
public String toString() {return "UserModel{" +
"name='" + name + '\'' +
", age=" + age +
", desc='" + desc + '\'' +
'}';
}
}

diByConstructorParamIndex.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-4.3.xsd">
<!-- 通过构造器参数的索引注入 -->
<bean id="diByConstructorParamIndex"
class="com.javacode2018.lesson001.demo5.UserModel">
<constructor-arg index="0" value="路人甲Java"/>
<constructor-arg index="1" value="我是通过构造器参数位置注入的"/>
</bean>
</beans>

上面创建UserModel实例代码相当于下面代码:

UserModel userModel = new UserModel("路人甲Java","我是通过构造器参数类型注入的");

工具类IoUtils.java

import org.springframework.context.support.ClassPathXmlApplicationContext;public class IocUtil {public static ClassPathXmlApplicationContext context(String beanXml) {return new ClassPathXmlApplicationContext(beanXml);
}
}

测试用例DiTest.java

import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* 公众号:路人甲Java,工作10年的前阿里P7分享Java、算法、数据库方面的技术干货!坚信用技术改变
命运,让家人过上更体面的生活!
*/
public class DiTest {/**
* 通过构造器的参数位置注入
*/
@Test
public void diByConstructorParamIndex() {String beanXml =
"classpath:/com/javacode2018/lesson001/demo5/diByConstructorParamIndex.xml";
ClassPathXmlApplicationContext context = IocUtils.context(beanXml);
System.out.println(context.getBean("diByConstructorParamIndex"));
}
}

参数位置的注入对参数顺序有很强的依赖性,若构造函数参数位置被人调整过,会导致注入出错。
不过通常情况下,不建议去在代码中修改构造函数,如果需要新增参数的,可以新增一个构造函数来实现,这算是一种扩展,不会影响目前已有的功能

根据构造器参数类型注入

用法:

<bean id="diByConstructorParamType"
class="com.javacode2018.lesson001.demo5.UserModel">
<constructor-arg type="参数类型" value="参数值"/>
<constructor-arg type="参数类型" value="参数值"/>
</bean>

constructor-arg用户指定构造器的参数
type:构造函数参数的完整类型,如:java.lang.String,int,double
value:构造器参数的值,value只能用来给简单的类型设置值

案例
diByConstructorParamType.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-4.3.xsd">
<!-- 通过构造器参数的类型注入 -->
<bean id="diByConstructorParamType"
class="com.javacode2018.lesson001.demo5.UserModel">
<constructor-arg type="int" value="30"/>
<constructor-arg type="java.lang.String" value="路人甲Java"/>
<constructor-arg type="java.lang.String" value="我是通过构造器参数类型注入
的"/>
</bean>
</beans>

相当于:

UserModel userModel = new UserModel("路人甲Java",30,"我是通过构造器参数类型注入的");

新增测试用例
DiTest类中新增一个测试用例

@Test
public void diByConstructorParamType() {String beanXml =
"classpath:/com/javacode2018/lesson001/demo5/diByConstructorParamType.xml";
ClassPathXmlApplicationContext context = IocUtils.context(beanXml);
System.out.println(context.getBean("diByConstructorParamType"));
}

运行diByConstructorParamType输出
UserModel{name=‘路人甲Java’, age=30, desc=‘我是通过构造器参数类型注入的’}

实际上按照参数位置或者按照参数的类型注入,都有一个问题,很难通过bean的配置文件,知道这个参数是对应UserModel中的那个属性的,代码的可读性不好,比如我想知道这每个参数对应UserModel中的那个属性,必须要去看UserModel的源码,下面要介绍按照参数名称注入的方式比上
面这2种更优秀一些。

根据构造器参数名称注入

<bean id="diByConstructorParamName"
class="com.javacode2018.lesson001.demo5.UserModel">
<constructor-arg name="参数类型" value="参数值"/>
<constructor-arg name="参数类型" value="参数值"/>
</bean>

constructor-arg用户指定构造器的参数
name:构造参数名称
value:构造器参数的值,value只能用来给简单的类型设置值

参数名称可能不稳定的问题,spring提供了解决方案,通过ConstructorProperties注解来定义参数的名称,将这个注解加在构造方法上面,如下:
@ConstructorProperties({“第一个参数名称”, “第二个参数的名称”,…“第n个参数的名称”})
public 类名(String p1, String p2…,参数n) {
}
案例
CarModel.java

public class CarModel {
private String name;
//描述信息
private String desc;
public CarModel() {
}
@ConstructorProperties({"name", "desc"})
public CarModel(String p1, String p2) {
this.name = p1;
this.desc = p2;
}
@Override
public String toString() {
return "CarModel{" +
"name='" + name + '\'' +
", desc='" + desc + '\'' +
'}';
}
}

diByConstructorParamName.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-4.3.xsd">
<!-- 通过构造器参数的名称注入 -->
<bean id="diByConstructorParamName"
class="com.javacode2018.lesson001.demo5.CarModel">
<constructor-arg name="desc" value="我是通过构造器参数类型注入的"/>
<constructor-arg name="name" value="保时捷Macans"/>
</bean>
</beans>

相当于:

CarModel carModel = new CarModel("保时捷Macans","我是通过构造器参数类型注入的");

增加测试类:

@Test
public void diByConstructorParamName() {String beanXml =
"classpath:/com/javacode2018/lesson001/demo5/diByConstructorParamName.xml";
ClassPathXmlApplicationContext context = IocUtils.context(beanXml);
System.out.println(context.getBean("diByConstructorParamName"));
}

输出:
CarModel{name=‘保时捷Macans’, desc=‘我是通过构造器参数类型注入的’}
通常情况下,我们的类都是标准的javabean,javabean类的特点:
属性都是private访问级别的
属性通常情况下通过一组setter(修改器)和getter(访问器)方法来访问
setter方法,以set 开头,后跟首字母大写的属性名,如:setUserName,简单属性一般只有一个方法参数,方法返回值通常为void;
getter方法,一般属性以get 开头,对于boolean类型一般以is 开头,后跟首字母大写的属性名,如:getUserName,isOk;
spring对符合javabean特点类,提供了setter方式的注入,会调用对应属性的setter方法将被依赖的对象注入进去。
型。
若我们依赖的对象是容器中的其他bean对象的时候,需要用下面的方式进行注入。
注入容器中的bean
注入容器中的bean有两种写法:
ref属性方式
内置bean的方式

  • ref属性方式
    将上面介绍的constructor-arg或者property元素的value属性名称替换为ref,ref属性的值为容器中其他bean的名称,如:
    构造器方式,将value替换为ref:
<constructor-arg ref="需要注入的bean的名称"/>

setter方式,将value替换为ref:

<property name="属性名称" ref="需要注入的bean的名称" />
  • 内置bean的方式
    构造器的方式:
<constructor-arg>
<bean class=""/>
</constructor-arg>

setter:

<property name="属性名称">
<bean class=""/>
</property>

案例
PersonModel.java

public class PersonModel {private UserModel userModel;
private CarModel carModel;
public PersonModel() {}
public PersonModel(UserModel userModel, CarModel carModel) {this.userModel = userModel;
this.carModel = carModel;
}
public UserModel getUserModel() {return userModel;
}
public void setUserModel(UserModel userModel) {this.userModel = userModel;
}
public CarModel getCarModel() {return carModel;
}
public void setCarModel(CarModel carModel) {this.carModel = carModel;
}
@Override
public String toString() {return "PersonModel{" +
"userModel=" + userModel +
", carModel=" + carModel +
'}';
}
}

PersonModel中有依赖于2个对象UserModel、CarModel,下面我们通过spring将UserModel和CarModel创建好,然后注入到PersonModel中,下面创建bean配置文件
diBean.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-4.3.xsd">
<bean id="user" class="com.javacode2018.lesson001.demo5.UserModel"></bean>
<!-- 通过构造器方式注入容器中的bean -->
<bean id="diBeanByConstructor"
class="com.javacode2018.lesson001.demo5.PersonModel">
<!-- 通过ref引用容器中定义的其他bean,user对应上面定义的id="user"的bean -->
<constructor-arg index="0" ref="user"/>
<constructor-arg index="1">
<bean class="com.javacode2018.lesson001.demo5.CarModel">
<constructor-arg index="0" value="宾利"/>
<constructor-arg index="1" value=""/>
</bean>
</constructor-arg>
</bean><!-- 通过setter方式注入容器中的bean -->
<bean id="diBeanBySetter"
class="com.javacode2018.lesson001.demo5.PersonModel">
<!-- 通过ref引用容器中定义的其他bean,user对应上面定义的id="user"的bean -->
<property name="userModel" ref="user"/>
<property name="carModel">
<bean class="com.javacode2018.lesson001.demo5.CarModel">
<constructor-arg index="0" value="保时捷"/>
<constructor-arg index="1" value=""/>
</bean>
</property>
</bean>
</beans>

测试类:

@Test
public void diBean(){String beanXml = "classpath:/com/javacode2018/lesson001/demo5/diBean.xml";
ClassPathXmlApplicationContext context = IocUtils.context(beanXml);
System.out.println(context.getBean("diBeanByConstructor"));
System.out.println(context.getBean("diBeanBySetter"));
}

出自公众号路人甲java

spring自定义作用域 依赖注入之手动注入相关推荐

  1. 【Spring】Spring 依赖注入之手动注入

    文章目录 1.概述 2.依赖回顾 2.依赖对象的初始化方式 2.1 通过构造器设置依赖对象 2.2 通过set方法设置依赖对象 3.spring依赖注入 3.1 通过构造器注入 3.1.1 根据构造器 ...

  2. 注入双括号报错注入_SQL手动注入:sqlilabs(less110)

    种一棵树最好的时间是10年前,其次是现在. 忘了是谁 前言 说实话,由于前段时间学 python ,对于 OWASP TOP10 漏洞的学习都有所落下,虽然现在也在慢慢复习当中,但是今晚谈及的 SQL ...

  3. Spring实现自动装配(spring注解详解)和手动注入比较

    概述 注释配置相对于 XML 配置具有很多的优势: 它可以充分利用 Java 的反射机制获取类结构信息,这些信息可以有效减少配置的工作.如使用 JPA 注释配置 ORM 映射时,我们就不需要指定 PO ...

  4. sql注入新手入门 从实战讲解SQL注入(手动注入+MySQL+靶场源码)

    资源放在下面,自取 https://blog.csdn.net/qq_45514735?spm=1011.2266.3001.5343 1.我们首先用小皮面板和sqli-labs靶场源码搭建一个环境 ...

  5. SpringBoot使用@Transactional的类手动注入失败

    一.手动注入失败解决方案     修改SpringBoot的默认动态代理模式,默认的是Java的动态代理模式,需要修改为CGLIB动态代理模式:     在application.properties ...

  6. Spring系列之依赖注入的三种方式

    目录 一.依赖注入方式 1.使用属性的setXXX方法注入 2.构造函数注入 (1)按类型匹配入参type (2)按索引匹配入参index (3)联合使用类型和索引匹配入参[type和index一起使 ...

  7. mockito手动注入依赖_依赖注入–手动方式

    mockito手动注入依赖 依赖注入是一种将行为与依赖解决方案分开的技术. 用简单的话来说,它使开发人员可以定义具有特定功能的类,这些功能取决于各种协作者,而不必定义如何获取对这些协作者的引用. 以此 ...

  8. 详解Spring框架的依赖注入

    本篇主要介绍Spring的依赖注入.依赖注入是Spring协调不同Bean实例之间的合作而提供的一种工作机制,在确保Bean实例之间合作的同时,并能保持每个Bean的相对独立性.通过本篇的学习,可以达 ...

  9. junit依赖_3、Spring 中的依赖注入(DI),你都知道多少?

    0. 前言 Spring 中,用来组成应用程序的主体以及由 Spring IoC 容器所管理的对象叫做 Bean.简而言之,Bean 就是由 IoC 容器来进行初始化.装配和管理的对象. Bean 的 ...

最新文章

  1. 解决Linux 无法使用userdel 删除用户和组的问题
  2. mybatis 中#和$的区别
  3. ios wkweb设置图片_iOS wkwebview和 uiwebview 内容图片自适应大小
  4. VS2013常用快捷键设置
  5. android view显示隐藏动画效果,Android 根据手势顶部View自动展示与隐藏效果
  6. 华为鸿蒙怎么体验,华为鸿蒙 HarmonyOS 2.0 发布,教你如何升级体验
  7. pytorch学习笔记(八):softmax回归的从零开始实现
  8. Adobe Premiere(Pr视频剪辑)下载安装
  9. 绿色奖学金申请答辩PPT模板
  10. python调用有道翻译_python调用有道云翻译api
  11. memcached入门使用
  12. mysql初始化密码_MySQL5.7初始密码查看及重置
  13. SSH远程登录与控制
  14. python 抠图源码_比PS还好用!Python 20行代码批量抠图
  15. 超详细!K8s 面试知识点
  16. vue 禁止input输入框输入特殊字符和汉字
  17. Thingsboard开源平台(一)2.软件安装
  18. ANSYS APDL经典界面如何导入多个材料模型
  19. win10下如何使用的debug
  20. 超好用一键卸载软件和软件注册码

热门文章

  1. 已锁定计算机,计算机锁定怎么解除_计算机已锁定如何解除
  2. 用javascript实现以下功能!_模电小实验:用三极管实现触摸开关功能
  3. tp3.2php开启事务,Thinkphp 3.2.3 开启调试模式
  4. labview求n阶乘的和_LABVIEW求1到N所有数的阶乘之和
  5. vs代码补全的快捷键_一款Python编程的自动补全插件神器——kite
  6. matlab sort三维_matlab练习题
  7. 多篇顶会论文看DRO (Distributionally Robust Optimization) 最新进展
  8. WWW 2021 | 通过强化学习控制对话式检索的风险
  9. B站疯传,一整套人工智能学习资料免费送,不谢!
  10. 如何应对Seq2Seq中的“根本停不下来”问题?