Spring IOC容器与Bean管理详解

一.IOC与DI

1. 传统的开发方式区别

对象直接引用导致对象硬性关联,程序难以扩展维护
在这里插入图片描述

loC容器是Spring生态的地基,用于统─创建与管理对象依赖
在这里插入图片描述

2. Spring IOC 控制反转

loC控制反转,全称Inverse of Control,是一种设计理念
由代理人来创建与管理对象,消费者通过代理人来获取对象
loC的目的是降低对象之间直接耦合
加入loC容器将对象统一管理,让对象关联变为弱耦合

Spring loC容器职责

对象的控制权交由第三方统一管理(loC控制反转)
利用Java反射技术实现运行时对象创建与关联(DI依赖注入)
基于配置提高应用程序的可维护性与扩展性
在这里插入图片描述

IOC初步体验

加载spring

<repositories><repository><id>aliyun</id><name>aliyun</name><url>https: //maven.aliyun.com/ repository/public</url></repository>
</repositories>
<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.6.RELEASE</version></dependency>
</dependencies>

引入spring

<?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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="sweetApple" class="com.imooc.spring.ioc.entity.Apple"><property name="title" value="红富士" ></property><property name="origin" value="欧洲" ></property><property name="color" value="红色" ></property></bean>
<beans>

实例:

public class Apple {private String title;private String color;private String origin;...}public class Child {private String name;private Apple apple;...public void eat(){System.out.println(name + "吃到了" + apple.getOrigin() + "种植物" + apple.getTitle());
}

传统方式:

Apple apple1 = new Apple("红富士","红色","欧洲");
Apple apple2 = new Apple("青苹果","绿色","中亚");
Apple apple3 = new Apple("金帅","黄色","中国");
Child lily = new Child("莉莉",apple1);
Child andy = new Child("安迪",apple2);
Child luna = new Child("露娜",apple3);
lily.eat();
andy.eat();
luna.eat(); 

引入spring后:

<?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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="sweetApple" class="com.imooc.spring.ioc.entity.Apple"><!--在Ioc容器启动时,自动由Spring实例化Apple对象,取名sweetApple放入到容器中--><property name="title" value="红富士" ></property><property name="origin" value="欧洲" ></property><property name="color" value="红色" ></property>
</bean>
<bean id="sourApple" class="com.imooc.spring.ioc.entity.Apple"><property name="title" value="青苹果" ></property><property name="origin" value="绿色" ></property><property name="color" value="中亚" ></property>
</bean>
<bean id="softApple" class="com.imooc.spring.ioc.entity.Apple"><property name="title" value="金帅" ></property><property name="origin" value="中国" ></property><property name="color" value="黄色" ></property>
</bean><bean id="lily" class="com.imooc.spring.ioc.entity.Child"><property name="name" value="莉莉"/><property name="apple" ref="softApple"/>
</bean>
<bean id="andy" class="com.imooc.spring.ioc.entity.Child"><property name="name" value="安迪"/><property name="apple" ref="sourApple"/>
</bean>
<bean id="luna" class="com.imooc.spring.ioc.entity.Child"><property name="name" value="露娜"/><property name="apple" ref="sweetApple"/>
</bean><beans>
public static void main(String[] args) {
//创建spring Ioc容器,并根据配置文件在容器中实例化对象ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");Apple sweetApple = context.getBean("sweetApple",Apple.class);System.out.println(sweetApple.getTitle());//从IoC容器中提取beanId-lily的对象Child lily = context.getBean("lily",Child.class);lily.eat();Child andy = context.getBean("andy",Child.class);andy.eat();Child luna = context.getBean("luna",Child.class);luna.eat();
}

3. DI依赖注入

loC是设计理念,是现代程序设计遵循的标准,是宏观目标
DI(Dependency Injection)是具体技术实现,是微观实现
DI在Java中利用反射技术实现对象注入(lnjection)

二.XML管理对象(Bean)

1.什么是java Bean
事实上就是有默认构造函数,属性私有并通过get与set方法属性设置组成的对象
2.三种配置方式

  • 基于XML配置Bean
  • 基于注解配置Bean
  • 基于Java代码(javaconfig)配置Bean
    3.基于XML配置Bean
    applicationContext.xml
<bean id="sweetApple" class="com.imooc.spring.ioc.entity.Apple"><property name="title" value="红富士" ></property><property name="origin" value="欧洲" ></property><property name="color" value="红色" ></property>
</bean>

XML方式创建IoC容器

//创建IoC容器并根据配置文件创建对象
ApplicationContext context = new ClassPathXmlApplicationContext(" classpath:applicationContext.xml");

实例化Bean的三种方式

  • 基于构造方法对象实例化
    • 默认构造方法实例化
<bean id="apple1" class="com.imooc.spring.ioc.entity.Apple">
</bean>
  • 带参构造方法实例化
1.利用构造方法参数名实例化
<bean id="sweetApple" class= "com.imooc.spring.ioc.entity.Apple">
<!--没有constructor-arg则代表调用默认构造方法实例化-->
<constructor-arg name="title" value="红富士"/>
<constructor-arg name="origin" value="欧洲"/>
<constructor-arg name="color" value="红色"/>
</bean>2.利用构造方法参数位置实例化
<bean id="sweetApple" class="com.imooc..spring.ioc.entity.Apple">
<!--利用构造方法参数位置实现对象实例化-->
<constructor-arg index="O" value="红富士"/>
<constructor-arg index="1" value="红色"/>
<constructor-arg index="2" value="欧洲"/>
</bean>

这里如果有数值类型的属性,那么在value写入的值是字符串类型,但是在构造方法中识别到这里是数值类型时会将这里的字符串自动转换为数值类型
如果在xml中只实例化两个属性,但在构造方法中却检测不到含有两个属性的构造方法,会报错
尽量按名称设置,因为按位置设置由于我的属性位置和构造方法中需要传入的值会有无意间的误差,导致运行结果的错误

  • 基于静态工厂实例化
静态工厂通过静态方法创建对象,隐藏创建对象的细节
public class AppleStaticFactory {public static Apple createSweetApple(){Apple apple = new Apple();apple.setTitle("红富士");apple.setOrigin("欧洲");apple.setColor("红色");return apple;}
}<bean id="apple3" class="com.imooc.spring.ioc.factory.AppleStaticFactory" factory-method="createSweetApple"/>
  • 基于工厂实例方法实例化
利用工厂实例方法获取对象
public class AppleFactoryInstance {public Apple createSweetApple(){Apple apple = new Apple();apple.setTitle("红富士");apple.setOrigin("欧洲");apple.setColor("红色");return apple;}
}
<bean id="factoryInstance" class="com.imooc.spring.ioc.factory.AppleFactoryInstance"/>
<bean id="apple4" factory-bean="factoryInstance" factory-method="createSweetApple"/>

从IoC容器获取Bean

Apple sweetApple = context.getBean("sweetApple",Apple.class);
或者
Apple sweetApple = (Apple)context.getBean("sweetApple");
System.out.println(sweetApple.getTitle());

id与name属性的相同点与不同点
id与name属性相同点

  • bean id与name都是设置对象在loC容器中唯一标识
  • 两者在同一个配置文件中都不允许出现重复
  • 两者允许在多个配置文件中出现重复,新对象覆盖旧对象
    id与name属性不同点
  • id要求更为严格,一次只能定义一个对象标识(推荐)
  • name更为宽松,一次允许定义多个对象标识
  • tips: id与name的命名要求有意义,按驼峰命名书写
没有id 与name的bean默认使用类名全称作为bean标识
<bean class="com.imooc..spring.ioc.entity.Apple">
<constructor-arg index="O" value="红富士三号"/>
<constructor-arg index="1" value="红色"/>
<constructor-arg index="2" value="欧洲"/>
</bean>
Apple apple = context.getBean ( s: "com.imooc.spring.ioc.entity.Apple",Apple.class) ;

路径匹配表达式
加载单个配置文件

//创建loC容器并根据配置文件创建对象
ApplicationContext context = new ClassPathXmlApplicationContext(" classpath:applicationContext.xml");

加载多个配置文件

String[] configLocations = newString[]{"classpath:applicationContext.xml"," classpath:applicationContext-1.xml"};
ApplicationContext context = new
ClassPathXmlApplicationContext(configLocations);

在这里插入图片描述

对象注入依赖
在这里插入图片描述

  • 依赖注入是指运行时将容器内对象利用反射赋给其他对象的操作
  • 基于setter方法注入对象
    • 利用setter实现静态数值注入
<bean id="sweetApple" class= "com.imooc.spring.ioc.entity.Apple">
<!--IoC容器自动利用反射机制运行时调用setXXX方法为属性赋值-->
<property name="title" value="红富士"/>
<property name="color" value="红色"/>
<property name="origin" value="欧洲"/>
</bean>
  • 利用setter实现对象注入
<bean id= "lily" class="com.imooc.spring.ioc.entity.Child">
<property name="name" value="莉莉"/>
<!--利用ref注入依赖对象-->
<property name="apple" ref= "sweetApple"/>  ref:关联
</bean>
  • 基于构造方法注入对象
public Child(String name, Apple apple) {System.out.println("构造方法参数apple::"+ apple);this.name = name;this.apple = apple;
}
<bean id="sourApple" class="com.imooc.spring.ioc.entity.Apple"><property name="title" value="青苹果"/><property name="origin" value="中亚"/><property name="color" value="绿色"/>
</bean><bean id="andy" class="com.imooc.spring.ioc.entity.Child"><constructor-arg name="name" value="安迪"/><constructor-arg name="apple" ref="sourApple"/>
</bean>
  • 注入依赖的优势

注入集合对象

注入List

<bean id="..." class="..."><property name= "someList"><list><value>具体值</alue><ref bean="beanld" ></ref></list></property>
</bean>

注入Set

<bean id="..." class="..."><property name= "someSet"><set><value>具体值</value><ref bean="beanld"></ref></set></property>
</bean>

注入Map

<bean id="..." class="..." ><property name="someMap"><map><entry key="k1" value="v1"></entry><entry key="k2" value-ref= "beanld" ></entry></map></property>
</bean>

注入Properties

<bean id="..." class="..." ><property name="someProperties"><props><prop key="k1">v1</prop><prop key="k2">v2</prop></props></property>
</bean>

查看容器内对象

//获取容器内所有beanId数组
string[ ] beanNames = context.getBeanDefinitionNames ();for (string beanName : beanNames ) {system. out.println (beanName) ;}

运行结果:

c1
company

写在外部的bean会被IoC检测Bean Id,写在内部的不会被检测

匿名对象使用办法

<bean class="com.imooc.spring.ioc.entity.Computer"><constructor-arg name="brand" value="微星"/><constructor-arg name="type" value="台式机"/><constructor-arg name="sn" value="8389280012"/><constructor-arg name="price" value="3000"/>
</bean><bean class="com.imooc.spring.ioc.entity.Computer"><constructor-arg name="brand" value="华硕"/><constructor-arg name="type" value="笔记本"/><constructor-arg name="sn" value="9089380012"/><constructor-arg name="price" value="6000"/>
</bean>

运行结果:

com.imooc.spring.ioc.entity.Computer#0
com.imooc.spring.ioc.entity.Computer#1

如果不加#X则默认调用第一个computer

Computer computer = context.getBean("com.imooc.spring.ioc.entity.Computer",Computer.class);
System.out.println(computer.getBrand());

运行结果:

微星

获取内容的方式:

String[] beanNames = context.getBeanDefinitionNames();
for (String beanName : beanNames) {System.out.println(beanName);System.out.println("类型:"+ context.getBean(beanName).getClass().getName());System.out.println("内容:"+ context.getBean(beanName).getClass().toString());
}

这里的toString可写可不写,因为这里默认调用toString方法

Bean Scope

定义:
bean scope属性用于决定对象何时被创建与作用范围
bean scope配置将影响容器内对象的数量
bean scope默认值singleton(单例),指全局共享同个对象实例
默认情况下bean会在loC容器创建后自动实例化,全局唯一
scope用法:

<bean id="bookDao"
class="com.imooc.spring.ioc.bookshop.dao.BookDaoOraclelmpl"
scope="prototype" />

bean scope属性清单
[图片]

singleton单例示意图
[图片]

解决问题:
IoC使用单例模式可以解决创建对象占用资源的问题,全局创建一次就行。
带来的问题是:
singleton在容器是单例多线程执行,存在线程安全风险
singleton的线程安全问题:
在这里插入图片描述

解决办法:
设置与读取的过程是独占状态,用户2的操作只有用户1操作完才行,多线程并行改成串行
prototype多例示意图
在这里插入图片描述

prototype在容器中多实例,占用更多资源,不存在线程安全问题
singleton和prototype的区别
在这里插入图片描述

IoC容器已初始化用到prototype,大多数用到的是singleton的单例

bean生命周期

在这里插入图片描述

实例:

public class Order {private Float price;private Integer quantity;private Float total;public Order(){System.out.println("创建Order对象:"+this);}public void init(){System.out.println("执行init方法");total = price * quantity;}public void pay() {System.out.println("订单金额为:"+ total);}public Float getPrice() {return price;}public void setPrice(Float price) {System.out.println("设置price:"+price);this.price = price;}public Integer getQuantity() {return quantity;}public void setQuantity(Integer quantity) {System.out.println("设置quantity:"+quantity);this.quantity = quantity;}public Float getTotal() {return total;}public void setTotal(Float total) {this.total = total;}public void destroy(){System.out.println("释放预订单相关的资源");}
}
<bean id="order1" class="com.imooc.spring.ioc.entity.Order" init-method="init" destroy-method="destroy"><property name="price" value="19.8"/><property name="quantity" value="1000"/>
</bean>
 ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");System.out.println("=====IoC容器已初始化=======");Order order1 = context.getBean("order1",Order.class);order1.pay();((ClassPathXmlApplicationContext) context).registerShutdownHook();

运行结果:

创建Order对象:com.imooc.spring.ioc.entity.Order@234bef66
设置price:19.8
设置quantity:1000
执行init方法
=====IoC容器已初始化=======
订单金额为:19800.0
释放预订单相关的资源

实现极简IoC容器

public class Apple {private String title;private String color;private String origin;
<?xml version="1.0" encoding="UTF-8"?>
<beans><bean id="sweetApple" class="com.imooc.spring.ioc.entity.Apple"><property name="title" value="富士红"/><property name="color" value="红色"/><property name="origin" value="欧洲"/></bean>
</beans>
public interface ApplicationContext {public Object getBean(String beanId);
}
public class ClassPathXmlApplicationContext implements ApplicationContext{private Map iocContainer = new HashMap();public ClassPathXmlApplicationContext(){try {String filePath = this.getClass().getResource("/applicationContext.xml").getPath();filePath= new URLDecoder().decode(filePath, "UTF-8");SAXReader reader = new SAXReader();Document document = reader.read(new File(filePath));List<Node> beans = document.getRootElement().selectNodes("bean");for (Node node: beans) {Element ele = (Element) node;String id = ele.attributeValue("id");String className = ele.attributeValue("class");Class c = Class.forName(className);Object obj = c.newInstance();List<Node> properties = ele.selectNodes("property");for (Node p:properties) {Element property = (Element) p;String propName = property.attributeValue("name");String propValue = property.attributeValue("value");String setMethodName = "set"+propName.substring(0,1).toUpperCase()+propName.substring(1);System.out.println("准备执行"+setMethodName+"方法注入数据");Method setMethod = c.getMethod(setMethodName, String.class);setMethod.invoke(obj,propValue);}iocContainer.put(id,obj);}System.out.println("IoC容器初始化完毕");}catch (Exception e){e.printStackTrace();}}@Overridepublic Object getBean(String beanId) {return iocContainer.get(beanId);}
}

运行结果

准备执行setTitle方法注入数据
准备执行setColor方法注入数据
准备执行setOrigin方法注入数据
IoC容器初始化完毕
com.imooc.spring.ioc.entity.Apple@7006c658

注解与Java Config

1.基于注解配置loC容器

1.基于注解的优势
摆脱繁琐的XML形式的bean与依赖注入配置
基于"声明式"的原则,更适合轻量级的现代企业应用
让代码可读性变得更好,研发人员拥有更好的开发体验
2.三类注解
组件类型注解-声明当前类的功能与职责
自动装配注解-根据属性特征自动注入对象
元数据注解-更细化的辅助loC容器管理对象的注解
3.四种组件类型注解
[图片]

例子:

<?xml version="1.0" encoding="UTF-8"?>
<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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsd"><!--在Ioc容器初始化时自动扫描四种组件类型注解并完成实例化@Repository@Service@Controller@component--><context:component-scan base-package="com.imooc"/>
</beans>
//组件类型注解默认beanId为类名首字母小写
@Repository("udao")
public class UserDao {
}
@Service
public class UserService {
}
@Controller
public class UserController {
}
@Component
public class StringUtils {}
public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");String[] ids = context.getBeanDefinitionNames();for (String id:ids) {System.out.println(id+":"+context.getBean(id));}
}

运行结果:

userController:com.imooc.spring.ioc.controller.UserController@5427c60c
udao:com.imooc.spring.ioc.dao.UserDao@15bfd87
userService:com.imooc.spring.ioc.service.UserService@543e710e
stringUtils:com.imooc.spring.ioc.utils.StringUtils@57f23557

4.开启组件扫描

<!--XML配置开启组件扫描,才能使用注解-->
<context:component-scan base-package= "com.imooc">
<!--正则表达式,不会被IoC扫描实例化-->
<context.exclude-filter type="regex" expression= "com.imooc.exl.*"/>
</context:component-scan>

5.两类自动装配注解
在这里插入图片描述

按类型注入的问题
@Autowired

@Service
public class UserService {public UserService() {System.out.println("正在创建UserService:"+this);}@Autowired//Spring Ioc容器会自动通过反射技术将属性private修饰符自动改为public,直接进行赋值,不再执行set方法//private->public->privateprivate UserDao udao;public UserDao getUdao() {return udao;}//@Autowired//如果装配注解放在set方法上,则自动按类型/名称对set方法参数进行注入public void setUdao(UserDao udao) {System.out.println("setUdao"+udao);this.udao = udao;}
}
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
UserService userService = context.getBean("userService",UserService.class);
System.out.println(userService.getUdao());

运行结果:

正在创建userDao:com.imooc.spring.ioc.dao.UserDao@306279ee
正在创建UserService:com.imooc.spring.ioc.service.UserService@545997b1
com.imooc.spring.ioc.dao.UserDao@306279ee

说明:如果运行结果没有setUdao,说明注入到属性中,没有在set方法上进行。
@Autowired装配注解本身问题
@Autowired

private IUserDao udao;public IUserDao getUdao() {return udao;
}
public interface IUserDao {
}
@Repository
public class UserDao implements IUserDao{public UserDao() {System.out.println("正在创建userDao:"+this);}
}@Repository
public class UserOracleDao implements IUserDao{public UserOracleDao() {System.out.println("正在创建UserOracleDao:"+this);}
}

会报错,不知道接口中那个Dao
解决办法:
方法一:去掉@Repository注解,不被Ioc容器去管理

public class UserDao implements IUserDao{public UserDao() {System.out.println("正在创建userDao:"+this);}
}

方法二:加上@Primary

@Repository
@Primary
public class UserOracleDao implements IUserDao{public UserOracleDao() {System.out.println("正在创建UserOracleDao:"+this);}
}

不推荐按类型装配
如果用注解进行对象依赖注入的话,通常不会创建set方法,多数情况下在属性上用到装配注解
按名称装配:
@Resource

@Service
public class DepartmentService {/*** 1. @Resource设置name属性,则按name在IoC容器中将bean注* 2.@Resource未设置name属性* 2.1 以属性名作为bean name在Ioc容器中匹配bean ,如有匹配则注入* 2.2按属性名未匹配,则按类型进行匹配,同@Autowired ,需加入@Primary解决类型冲突*使用建议:在使用@Resource对象时推荐设置name或保证属性名与bean名称一致*/@Resourceprivate IUserDao userOracleDao;public void joinDepartment(){System.out.println(userOracleDao);}
}

6.元数据注解
在这里插入图片描述

config.properties文件

metaData=imooc.com
connection.driver=xxxxx
connection.url=xxxxx
connection.username=xxxxx
connection.password=xxxxx

xml配置文件

<context:property-placeholder location="classpath:config.properties"/>
@Service
@Scope("prototype")//设置单例/多例,XML中 bean scope完全相同
public class UserService {@Value("${metaData}")//读取config.properties的metaData属性值private String metaData;@Value("${connection.password}")private String password;public UserService() {System.out.println("正在创建UserService:"+this);}@PostConstruct//XML中bean init-method完全相同public void init(){System.out.println("初始化UserService对象,metaData="+metaData);}

Java Config配置loC容器

1.优势
完全摆脱XML的束缚,使用独立Java类管理对象与依赖
注解配置相对分散,利用Java Config可对配置集中管理
可以在编译时讲行依赖检查不容易出错
2.java Config核心注解
在这里插入图片描述

对象的实例化

public class UserDao {
}public class UserService {private UserDao userDao ;...
}public class UserController {private UserService userService;...
}
@Configuration//当前类是一个配置类,用于替代applicationContext.xml
public class Config {@Bean//Java Config利用方法创建对象,将方法返回对象放入容器,beanId=方法名public UserDao userDao(){UserDao userDao = new UserDao();return userDao;}@Beanpublic UserService userService(){UserService userService = new UserService();return userService;}@Beanpublic UserController userController(){UserController userController = new UserController();return userController;}
}
public class SpringApplication {public static void main(String[] args) {//基于Java Config配置工oC容器的初始化ApplicationContext context = new AnnotationConfigApplicationContext(Config.class);String[] ids = context.getBeanDefinitionNames();for (String id:ids) {System.out.println(id + ":" + context.getBean(id));}}
}

运行结果

org.springframework.context.annotation.internalConfigurationAnnotationProcessor:org.springframework.context.annotation.ConfigurationClassPostProcessor@4d49af10
org.springframework.context.annotation.internalAutowiredAnnotationProcessor:org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor@279ad2e3
org.springframework.context.annotation.internalCommonAnnotationProcessor:org.springframework.context.annotation.CommonAnnotationBeanPostProcessor@58134517
org.springframework.context.event.internalEventListenerProcessor:org.springframework.context.event.EventListenerMethodProcessor@4450d156
org.springframework.context.event.internalEventListenerFactory:org.springframework.context.event.DefaultEventListenerFactory@4461c7e3
config:com.imooc.spring.ioc.Config$$EnhancerBySpringCGLIB$$c42995d4@351d0846
userDao:com.imooc.spring.ioc.dao.UserDao@77e4c80f
userService:com.imooc.spring.ioc.service.UserService@35fc6dc4
userController:com.imooc.spring.ioc.controller.UserController@7fe8ea47

对象依赖注入
这里java Config的依赖注入中,用到注解形式和在xml中一样

@Configuration//当前类是一个配置类,用于替代applicationContext.xml
@ComponentScan(basePackages = "com.imooc")
public class Config {@Bean//Java Config利用方法创建对象,将方法返回对象放入容器,beanId=方法名public UserDao userDao(){UserDao userDao = new UserDao();System.out.println("已创建"+userDao);return userDao;}@Bean@Primarypublic UserDao userDao1(){UserDao userDao = new UserDao();System.out.println("已创建"+userDao);return userDao;}@Bean//先按name尝试注入,name不存在则按类型注入public UserService userService(UserDao userDao , EmployeeDao employeeDao){UserService userService = new UserService();System.out.println("已创建"+userDao);userService.setUserDao(userDao);System.out.println("调用setUserDao"+userDao);userService.setEmployeeDao(employeeDao);return userService;}@Bean//<bean id="xxx" class="xxx">@Scope("prototype")public UserController userController(UserService userService){UserController userController = new UserController();System.out.println("已创建"+userService);userController.setUserService(userService);System.out.println("调用setUserService"+userService);return userController;}
}

Java Config与xml的利弊
Java Config好处在于能在编写代码初期就能识别代码对错,而xml无法快速定位错误
Java Config的开发体验好,对象被集中管理和创建,但是是java的源代码,在产品发布后要调整,必须重新编译才行,这种方式用于开发工作中敏捷开发中快速迭代,快速上线的工程
xml用于大型项目,通过配置文件来划分不同团队各司其职
Java Config有好的开发体验,xml有更好的程序可维护性
Spring Test测试模块
Spring Test是Spring中用于测试的模块
Spring Test对JUnit单元测试框架有良好的整合
通过Spring Test可在JUnit在单元测试时自动初始化loC容器

Spring与JUnit4整合过程

  • Maven工程依赖spring-test
  • 利用@RunWith与@ContextConfiguration描述测试用例类
    • @RunWith:将junit4的运行过程交给spring完成,通过这个注解让spring来接管junit4的控制权,完成IoC的初始化工作
    • @ContextConfiguration:用于说明我们在初始化Ioc容器过程中要加载那些配置文件
  • 测试用例类从容器获取对象完成测试用例的执行

加载junit4和test测试

 <dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.2.6.RELEASE</version>
</dependency>
<dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope>
</dependency>
public class UserDao {public void insert(){System.out.println("新增用户数据");}
}public class UserService {private UserDao userDao;public void createUser(){System.out.println("调用创建用户业务代码");userDao.insert();}...
}
<bean id="userDao" class="com.imooc.spring.ioc.dao.UserDao"></bean><bean id="userService" class="com.imooc.spring.ioc.service.UserService"><property name="userDao" ref="userDao"/>
</bean>
//将Junit4的执行权交由Spring Test,在测试用例执行前自动初始化IoC容器
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public class SpringTestor {@Resourceprivate UserService userService;@Testpublic void testUserService(){userService.createUser();}
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

请允许自己偶尔情绪不稳定

最近看网上的讨论&#xff0c;发现一件事&#xff1a;许多人都把「情绪稳定」当作一个很难得的优点&#xff0c;狂热地去追捧。 什么叫情绪稳定呢&#xff1f;大抵指这些&#xff1a; 遇到问题时不容易发火或沮丧&#xff0c;而是能立刻切换成解决问题的视角&#xff1b; 心情…

Windows系统使用Docker部署Focalboard团队协作工具详细流程

文章目录 前言1. 使用Docker本地部署Focalboard1.1 在Windows中安装 Docker1.2 使用Docker部署Focalboard 2. 安装Cpolar内网穿透工具3. 实现公网访问Focalboard4. 固定Focalboard公网地址 前言 本篇文章将介绍如何使用Docker本地部署Focalboard项目管理工具&#xff0c;并且结…

微信小程序打印功能怎么用?

在数字化时代&#xff0c;微信小程序为我们提供了许多便捷的服务&#xff0c;其中就包括打印功能。而琢贝云打印小程序&#xff0c;作为一款功能强大、操作简便的线上打印平台&#xff0c;更是受到了广大用户的青睐。下面&#xff0c;我将为大家介绍如何使用琢贝云打印小程序完…

下雨天的短视频:成都鼎茂宏升文化传媒公司

下雨天的短视频&#xff1a;捕捉雨中的诗意与温情 在快节奏的现代生活中&#xff0c;短视频以其独特的魅力成为了人们记录生活、分享情感的重要工具。而下雨天&#xff0c;这个常常带有诗意与温情的场景&#xff0c;更是为短视频创作者们提供了无尽的灵感源泉。成都鼎茂宏升文…

Spring常用注解(超全面)

官网&#xff1a;核心技术SPRINGDOC.CN 提供 Spring 官方文档的翻译服务&#xff0c;可以方便您快速阅读中文版官方文档。https://springdoc.cn/spring/core.html#beans-standard-annotations 1&#xff0c;包扫描组件标注注解 Component&#xff1a;泛指各种组件 Controller、…

9. C++通过epoll+fork的方式实现高性能网络服务器

epollfork 实现高性能网络服务器 一般在服务器上&#xff0c;CPU是多核的&#xff0c;上述epoll实现方式只使用了其中的一个核&#xff0c;造成了资源的大量浪费。因此我们可以将epoll和fork结合来实现更高性能的网络服务器。 创建子进程函数–fork( ) 要了解线程我们先来了解…

近五年营收和净利润大幅“败北”,尚品宅配今年押注扩张加盟

​ 《港湾商业观察》廖紫雯 两个月前经历过高管公开信的尚品宅配&#xff08;300616.SZ&#xff09;&#xff0c;无论是2023年年报&#xff0c;还是今年一季报&#xff0c;虽然公司净利润表现尚佳&#xff0c;但收入端的持续承压仍然备受关注。 今年一季报&#xff0c;尚品宅…

Prometheus监控平台配置--监控集群资源信息

之前我们介绍的都是对单机的监控&#xff0c;今天介绍下用Prometheus对集群多台机器的系统资源进行监控。 我们需要在被压测服务器上安装 node_exporter和mysql_exporter&#xff0c;通过这两个工具对操作系统和mysql进行监控&#xff0c;将收集的数据存储到Prometheus&#xf…

快速版-JS基础01书写位置

1.书写位置 2.标识符 3.变量 var&#xff1a;声明变量。 &#xff08;1&#xff09;.变量的重新赋值 &#xff08;2&#xff09;.变量的提升 打印结果&#xff1a;console.log(变量名) 第一个是你写在里面的。 第二个是实际运行的先后之分&#xff0c;变量名字在最前面。变量…

Delphi 开发Android Service四种模式初探

前言&#xff1a; 本篇文章正经来说&#xff0c;其实算是我的学习履历&#xff0c;是我在不断的摸索过程中&#xff0c;总结的经验&#xff0c;不能算是一篇正经的学术文章。现在DELPHI的学习资料太少了&#xff0c;就算是有也都是基于老版本DELPHI&#xff0c;或VCL相关的内容…

26计算机操作系统408考研--操作系统设备管理篇章(五)

文章目录 一、设备是什么&#xff1f;设备管理目标和任务I/O设备分类 二、I/O系统控制方式程序直接控制方式中断控制方式DMA控制方式通道控制方式 I/O软件的组成I/O软件设计目标和原则I/O软件结构设备驱动程序设备无关软件用户层软件用户层的I/O软件 具有通道的设备管理通 道通…

Day37 代码随想录打卡|二叉树篇---对称二叉树

题目&#xff1a; 给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 方法&#xff1a;本体可以用递归和迭代两种方法&#xff0c;但我更喜欢迭代的方式&#xff0c;因此使用迭代的方式做一下。首先我们分析一下不对称的情况。因为对称的情况很简单&#xff0c;即两…

实现一个简单的 Google Chrome 扩展程序

目录 &#x1f9ed; 效果展示 # 图示效果 a. 拓展程序列表图示效果&#xff1a; b. 当前选项卡页面右键效果&#xff1a; c. 拓展程序消息提示效果&#xff1a; &#x1f4c7; 项目目录结构 # 说明 # 结构 # 文件一览 ✍ 核心代码 # manifest.json # background.j…

星融元获2024网络开源优秀创新成果奖!

5月25日&#xff0c;星融元受邀参加2024年第四届网络开源技术生态大会&#xff0c;分享主题为“开放的网络 开放的AI生态”主题演讲&#xff0c;深受现场用户的认可&#xff1b;《Easy RoCE&#xff1a;基于SONiC、Klish和Prometheus的极简无损网络解决方案》获得2024网络开源优…

SpheroGPT: 声控自然语言编程 AI 玩具 Demo 具身智能 图文解说 完全开源机器人

背景介绍 因为生病请了长假. 一周前状态开始恢复, 于是尝试用 LLM (ChatGPT3.5) + Sphero 开发一个可以声控自然语言编程的 AI 玩具, 作为学习 ChatGPT 应用开发的方法. 差不多十天时间把开发目标基本都实现了, 这里和大家分享一下心得体会. Demo 示例视频 先把录制的几个 d…

云原生Kubernetes: 云主机部署K8S 1.30版本 单Master架构

目录 一、实验 1.环境 2.Termius连接云主机 3.网络连通性与安全机制 4.云主机部署docker 5.云主机配置linux内核路由转发与网桥过滤 6.云主机部署cri-dockerd 7.云主机部署kubelet,kubeadm,kubectl 8.kubernetes集群初始化 9.容器网络&#xff08;CNI&#xff09;部署…

Docker学习笔记 - 创建自己的image

目录 基本概念常用命令使用docker compose启动脚本创建自己的image 使用Docker是现在最为流行的软件发布方式&#xff0c; 本系列将阐述Docker的基本概念&#xff0c;常用命令&#xff0c;启动脚本和如何生产自己的docker image。 在我们发布软件时&#xff0c;往往需要把我…

解析边缘计算网关的优势-天拓四方

随着信息化、智能化浪潮的持续推进&#xff0c;计算技术正以前所未有的速度发展&#xff0c;而边缘计算网关作为其中的重要一环&#xff0c;以其独特的优势正在逐步改变我们的生活方式和工作模式。本文将详细解析边缘计算网关的优势。 首先&#xff0c;边缘计算网关具有显著的…

uniapp页面vue3下拉触底发送获取新数据请求实现分页功能

页面下拉触底获取新数据实现分页功能实现方式有两种&#xff0c;根据自己的业务需求来定&#xff0c;不同的方案适用场景不一样&#xff0c;有的是一整个页面下拉获取新数据&#xff0c;有的是部分盒子内容滚动到底部时候实现获取新数据&#xff0c;下面讨论一下两种方式的区别…

JSON-RPC跨域通信:Python服务器端解决方案与Js客户端 Mozilla扩展程序

问题背景 构建一个 Mozilla 扩展程序&#xff0c;与远程服务器上的 Python 应用程序进行通信以发送和接收数据。Python 应用程序可以通过 Python 控制台使用 xml-rpc 调用。尝试设计一个 JSON-RPC 来联系同一个应用程序。开发 Python 服务器端&#xff0c;可以通过 python 控制…