Spring面试篇章——IOC
IOC概念和原理
IOC概念
- IOC就是控制反射,把对象创建和对象之间的调用过程,交给Spring进行管理
- 使用IOC的目的:降低耦合度
IOC底层原理
- xml解析、工厂模式、反射
图解:
原始模式

- 耦合度太高了,即当dao改了,service也跟着要改
工厂模式

- 工厂模式目的:使耦合度降低到最低限度,降低service和dao之间的联系
IOC过程

IOC(BeanFactory、ApplicationContext接口)
-
IOC思想基于IOC容器完成,IOC容器底层就是对象工厂,本质上就是一个工厂
-
Spring提供IOC容器实现两种方式:(两个接口)
-
- BeanFactory:IOC容器基本实现,是Spring内部的使用接口,不提供开发人员进行使用
特点:加载配置文件的时候不会创建对象,在获取对象(使用)才去创建对象
即BeanFactory在加载spring配置文件的时候,不会创建对象,只有在获取对象要去使用的时候才会去创建对象
-
- ApplicationContext:BeanFactory接口的子接口,提供更多更强大的功能,一般由开发人员进行使用
特点:加载配置文件的时候就会把在配置文件的对象进行创建
而ApplicationContext在加载spring配置文件的时候,就会创建对象
- ApplicationContext接口有实现类

- FileSystemXmlApplicationContext这个实现类,里面传入的是xml文件的磁盘位置,比如:D:/java/bean1.xml
- 而ClassPathXmlApplicationContext这个实现类,里面传入的是类路径,即src下

IOC操作Bean管理
- Bean管理指的是两个操作:
- Spring创建对象
- Spring注入属性
- Bean管理操作有两种方式:
- 基于xml配置文件方式实现
- 基于注解方式实现
💖IOC操作Bean管理(基于xml方式)
基于xml方式创建对象
<!--配置User类的对象的创建-->
<!-- id就是起个名字(别名),class中填入这个类的全路径 -->
<bean id="user" class="com.zan.spring5.User"></bean>
做法:
-
在Spring配置文件中,使用bean标签,标签里面添加对应属性,就可以实现对象创建
-
在bean标签中有很多属性,常用属性
-
- id属性:唯一标识,也相当于别名
- class属性,类全路径(即包名+类名)
- name属性:跟id属性一样,作为唯一标识,但是用的很少,name的区别就是可以使用特殊符号,如:/
-
创建对象时候,默认是执行类的无参构造器来完成对象的创建
- 因此如果类中没有无参构造器,则会报错,因为找不到

- 没有无参构造器,报错

基于xml方式注入属性
- DI:依赖注入,就是注入属性
使用set方法进行注入属性
- 原始方法(以前的方法来注入属性)

- 现用Spring来进行注入属性
- 创建类,定义属性和对应的set方法
/*** 演示使用set方法进行注入属性*/
public class Book {//创建属性private String bname;private String bauthor;//创建属性对应的set方法注入public void setBname(String bname) {this.bname = bname;}public void setBauthor(String bauthor) {this.bauthor = bauthor;}//测试方法,用来看是否注入成功public void testDemo() {System.out.println(bname + " : " + bauthor);}
}
- 在Spring的配置文件xml中配置对象创建,配置属性注入
<!--set方法注入属性-->
<bean id="book" class="com.zan.spring5.Book"><!--在bean标签里面使用property,用来完成属性的注入name:类里面属性名称value:注入的属性值--><property name="bname" value="abc"></property><property name="bauthor" value="zan哥"></property>
</bean>

- 测试结果

使用有参构造器注入属性
- 原始方法(以前的方法来注入属性)

- 现用Spring来进行注入属性
- 创建类,定义属性,创建属性对应的有参构造方法
package com.zan.spring5;/*** 使用有参构造器注入属性*/
public class Orders {private String oname;private String address;public Orders(String oname, String address) {this.oname = oname;this.address = address;}public void ordersTest() {System.out.println(oname + " : " + address);}
}
- 在Spring的配置文件xml中进行配置
<!--用有参构造器注入属性-->
<bean id="order" class="com.zan.spring5.Orders"><!-- <constructor-arg name="oname" value="电脑"></constructor-arg>--><constructor-arg name="address" value="China"></constructor-arg><constructor-arg index="0" value="电脑1"></constructor-arg>
</bean>
- 这个可以使用name来表示属性的,也可以用index来表示属性

- 使用index来代表属性

p名称空间注入(了解)
- 使用p名称空间注入,可以简化基于xml配置方式
- 添加 p 名称空间在配置文件中
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:p="http://www.springframework.org/schema/p"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
- beans标签的头内容其实是xml的相关约束
- 进行属性注入,在bean标签里面进行操作
<bean id="book" class="com.zan.spring5.Book" p:bname="abcd" p:bauthor="Zan大哥"></bean>

基于xml方式注入属性(其他类型属性)
字面值
- null值
<!--设置一个null值,空值-->
<property name="address"><null/>
</property>

- 属性值包含特殊符号

<!--属性值中包含特殊符号,如 <>解决方法: 1. 将<> 进行转义,即< >2. 把带特殊符号内容写到CDATA中
-->
<property name="address"><value><![CDATA[<<南京>>]]></value>
</property>
- 这个格式快捷键 - CD

注入属性 - 外部bean
- 创建两个类service类和dao类
- 在service中调用dao里面的方法
public class UserDaoImpl implements UserDao{@Overridepublic void update() {System.out.println("dao update...........");}
}public class UserService {//创建UserDao类型属性,生成set方法private UserDao userDao;public void setUserDao(UserDao userDao) {this.userDao = userDao;}public void add() {System.out.println("service add..........");userDao.update();//创建UserDao对象 - 原始方式//UserDao userDao = new UserDaoImpl();//userDao.update();}
}
- 在Spring配置文件中进行配置
<!--1. service和dao对象创建-->
<bean id="userService" class="com.zan.spring5.service.UserService"><!--注入userDao对象name:类里面的属性名称ref:创建的userDao对象里面bean标签的id值--><property name="userDao" ref="userDaoImpl"></property>
</bean><bean id="userDaoImpl" class="com.zan.spring5.dao.UserDaoImpl"></bean>

注入属性 - 内部bean
一对多关系:部门和员工,一个部分有多个员工,一个员工属于一个部分,部门是一,员工是多
- 在实体类之间表示一对多关系,员工表示所属部门,使用对象类型属性进行表示
//部门类
public class Dept {private String dname;public void setDname(String dname) {this.dname = dname;}
}
//员工类
public class Emp {private String ename;private String gender;//员工属于某一个部门,使用对象形式表示private Dept dept;public void setDept(Dept dept) {this.dept = dept;}public void setEname(String ename) {this.ename = ename;}public void setGender(String gender) {this.gender = gender;}
}
在spring配置文件中进行配置
<!--内部bean-->
<bean id="emp" class="com.zan.spring5.bean.Emp"><!--先设置两个普通的属性--><property name="ename" value="lucy"></property><property name="gender" value="女"></property><!--设置对象类型属性--><property name="dept"><bean id="dept" class="com.zan.spring5.bean.Dept"><property name="dname" value="安保部"></property></bean></property>
</bean>

注入属性 - 级联赋值
第一种写法
<!--级联赋值--><bean id="emp" class="com.zan.spring5.bean.Emp"><!--先设置两个普通的属性--><property name="ename" value="lucy"></property><property name="gender" value="女"></property><!--级联赋值--><property name="dept" ref="dept"></property></bean><bean id="dept" class="com.zan.spring5.bean.Dept"><property name="dname" value="财务部"></property></bean>

第二种写法
- 首先要先给dept这个属性设置get方法
//生成dept的get方法
public Dept getDept() {return dept;
}
<!--级联赋值--><bean id="emp" class="com.zan.spring5.bean.Emp"><!--先设置两个普通的属性--><property name="ename" value="lucy"></property><property name="gender" value="女"></property><!--级联赋值--><property name="dept" ref="dept"></property><property name="dept.dname" value="教学部"></property></bean><bean id="dept" class="com.zan.spring5.bean.Dept"></bean>

注入集合属性
- 注入数组类型、List集合类型、Map集合类型、Set集合类型属性
- 创建类,定义数组、List、Map、Set类型属性,生成对应的set方法
package com.zan.spring5.collectiontype;import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;public class Stu {//1. 数组类型属性private String[] courses;//课程//2. List集合类型属性private List<String> list;//3. Map集合类型属性private Map<String, String> map;//4. set集合类型属性private Set<String> sets;//学生所学多门课程private List<Course> courseList;public void setCourseList(List<Course> courseList) {this.courseList = courseList;}public void setCourses(String[] courses) {this.courses = courses;}public void setList(List<String> list) {this.list = list;}public void setMap(Map<String, String> map) {this.map = map;}public void setSets(Set<String> sets) {this.sets = sets;}//测试方法public void test() {System.out.println(Arrays.toString(courses));System.out.println(list);System.out.println(map);System.out.println(sets);System.out.println(courseList);}
}
- 在Spring配置文件xml中进行配置
<!--集合类型属性的注入-->
<bean id="stu" class="com.zan.spring5.collectiontype.Stu"><!--数组类型属性注入--><property name="courses"><array><value>Java课程</value><value>C++课程</value></array></property><!--list类型属性注入--><property name="list"><list><value>小三</value><value>张三</value></list></property><!--map类型属性注入--><property name="map"><map><entry key="JAVA" value="java"/><entry key="JSP" value="jsp"/></map></property><!--set类型属性注入--><property name="sets"><set><value>MySQL</value><value>Redis</value></set></property>
- 数组类型可以用array标签,也可以用list标签

细节问题
- 在集合里面设置对象类型值
<!--创建多个course对象,将course对象传过去即可-->
<bean id="course1" class="com.zan.spring5.collectiontype.Course"><property name="cname" value="Spring5框架课程"/>
</bean>
<bean id="course2" class="com.zan.spring5.collectiontype.Course"><property name="cname" value="MyBatis框架课程"/>
</bean><bean><!--注入list集合类型,值是对象--><property name="courseList"><list><ref bean="course1"/><ref bean="course2"/></list></property>
</bean>


- 把集合注入部分提取出来
(a)在Spring配置文件xml中引入名称空间util
- 在xml文件中的约束文件处引入名称空间util
<?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:util="http://www.springframework.org/schema/util"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
</beans>

(b)使用util标签完成list集合注入提取
<!--提取list集合类型属性的注入-->
<util:list id="bookList"><value>Java核心技术卷1</value><value>Java核心技术卷2</value><value>MySQL数据库</value>
</util:list><!--提取list集合类型属性注入使用-->
<bean id="book" class="com.zan.spring5.collectiontype.Book"><property name="list" ref="bookList"></property>
</bean>

IOC操作Bean管理(FactoryBean)
- Spring有两种类型bean,一种普通bean,另外一种工厂bean(FactoryBean)
- 普通bean:在配置文件中定义bean类型就是返回类型
- 工厂bean:在配置文件定义bean类型可以和返回类类型不一样
实现步骤:
(a)创建类,让这个类作为工厂bean,即****实现接口FactoryBean
(b)实现接口里面的方法,在实现的方法中定义返回的bean类型
package com.zan.spring5.factorybean;import com.zan.spring5.collectiontype.Course;
import org.springframework.beans.factory.FactoryBean;public class MyBean implements FactoryBean<Course> {//定义返回bean对象,即返回类型@Overridepublic Course getObject() throws Exception {Course course = new Course();course.setCname("abc");return course;}@Overridepublic Class<?> getObjectType() {return null;}@Overridepublic boolean isSingleton() {return FactoryBean.super.isSingleton();}
}
<bean id="myBean" class="com.zan.spring5.factorybean.MyBean"></bean>
- 注意:这里的测试类的getBean里面获取的类应该是我们返回的类型,即是Course,不然会报类型不匹配错误


IOC操作Bean管理(bean作用域)
- 在Spring中,我们可以设置bean示例是单实例或者多实例
- 在Spring中,默认情况下,bean是单实例对象
单实例:地址一样
多实例:地址不一样
@Test
public void testBook() {ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");Book book1 = context.getBean("book", Book.class);Book book2 = context.getBean("book", Book.class);System.out.println(book1);System.out.println(book2);}

-
设置单实例或多实例
-
- 在Spring配置文件中的bean标签里面有属性(scope)用于设置单实例还是多实例
- scope:有两个值,singleton单实例(默认),prototype多实例
<!--提取list集合类型属性的注入-->
<util:list id="bookList"><value>Java核心技术卷1</value><value>Java核心技术卷2</value><value>MySQL数据库</value>
</util:list><!--提取list集合类型属性注入使用-->
<bean id="book" class="com.zan.spring5.collectiontype.Book" scope="prototype"><property name="list" ref="bookList"></property>
</bean>

- singleton和prototype区别
- singleton单实例,prototype多实例
- 设置scope值是singleton时,测试文件在加载Spring配置文件的时候就会创建单实例对象,因此这时的地址就已经确定,之后创建的对象都是同一个地址
设置scope值是prototype时,测试文件不是在加载Spring配置文件的时候创建对象,而是在调用getBean方法的时候创建多实例对象
IOC操作Bean管理(bean生命周期)
生命周期:从对象创建到对象销毁的过程
bean生命周期:
- 通过构造器创建bean实例(无参数构造器)
- 为bean的属性设置值和对其他bean的引用(调用set方法)
- 调用bean的初始化的方法(需要进行配置初始化的方法)
- bean可以使用了(对象获取到了)
- 当容器关闭的时候,调用bean的销毁的方法(需要进行配置销毁的方法)
- 注意:第三步初始化和第五步销毁都要自己额外配置
演示bean的生命周期
package com.zan.spring5.bean;public class Orders {private String oname;public Orders() {System.out.println("第一步 执行无参构造器创建bean实例");}public void setOname(String oname) {this.oname = oname;System.out.println("第二步 调用set方法设置属性值");}//创建初始化的方法public void init() {System.out.println("第三步 调用初始化的方法");}//创建销毁的方法public void destroy() {System.out.println("第五步 调用销毁的方法");}
}
- 在bean标签中设置初始化init-method和销毁destory-method
<bean id="orders" class="com.zan.spring5.bean.Orders" init-method="init" destroy-method="destroy"><property name="oname" value="手机"></property>
</bean>
- 测试方法:
@Test
public void testBean3() {//ApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml");ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml");Orders orders = context.getBean("orders", Orders.class);System.out.println("第四步 获取创建bean实例对象");System.out.println(orders);//手动让bean销毁,才会调用bean销毁的方法,这个close是在ClassPathXmlApplicationContext这个实现类里面的//((ClassPathXmlApplicationContext)context).close();context.close();
}

其实,bean的生命周期还有两步,即七步
bean的后置处理器:
1)通过构造器创建 bean 实例(无参数构造)
2)为 bean 的属性设置值和对其他 bean 引用(调用 set 方法)
3)把 bean 实例传递 bean 后置处理器的方法 postProcessBeforeInitialization
4)调用 bean 的初始化的方法(需要进行配置初始化的方法)
5)把 bean 实例传递 bean 后置处理器的方法 postProcessAfterInitialization
6)bean 可以使用了(对象获取到了)
7)当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)
- 即添加在初始化之前和初始化之后
- 要想添加这两步,需要有一个类去实现BeanPostProcessor接口
- 创建类,实现接口BeanPostProcessor,创建后置处理器
package com.zan.spring5.bean;import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;public class MyBeanPost implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println("在初始化之前执行的方法");return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("在初始化之后执行的方法");return bean;}
}
- 配置后置处理器
<!--配置后置处理器对当前的所有bean都添加后置处理器
-->
<bean id="myBeanPost" class="com.zan.spring5.bean.MyBeanPost"></bean>

IOC操作Bean管理(xml自动装配)【用的很少,一般都用注解】
自动装配:根据指定装配规则(属性名称或者属性类型),Spring自动将匹配的属性值进行注入【之前的指定name和value,是手动装配】
package com.zan.spring5.autowire;public class Dept {@Overridepublic String toString() {return "Dept{}";}
}
package com.zan.spring5.autowire;public class Emp {private Dept dept;public void setDept(Dept dept) {this.dept = dept;}@Overridepublic String toString() {return "Emp{" +"dept=" + dept +'}';}public void test() {System.out.println(dept);}
}
根据属性名称自动注入
<!--实现自动装配bean标签属性autowire,配置自动装配autowire属性常用两个值:byName根据属性名称注入,注入的值bean的id的值要和类里面属性的名称一样byType根据属性的类型注入
-->
<bean id="emp" class="com.zan.spring5.autowire.Emp" autowire="byName">
<!-- <property name="dept" ref="dept"></property>-->
</bean>
<bean id="dept" class="com.zan.spring5.autowire.Dept"></bean>

根据属性类型自动注入
<!--实现自动装配bean标签属性autowire,配置自动装配autowire属性常用两个值:byName根据属性名称注入,注入的值bean的id的值要和类里面属性的名称一样byType根据属性的类型注入
-->
<bean id="emp" class="com.zan.spring5.autowire.Emp" autowire="byType">
<!-- <property name="dept" ref="dept"></property>-->
</bean>
<bean id="dept" class="com.zan.spring5.autowire.Dept"></bean>

- 注意:用类型会不太好,因为如果有两个类都是Dept类,那么它将会不知道要使用哪个Dpet
IOC操作Bean管理(外部属性文件)
-
直接配置数据库信息
-
- 配置德鲁伊连接池
- 引入德鲁伊连接池依赖jar包
<!--直接去配置连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property><property name="url" value="jdbc:mysql://localhost:3306/atguigu"></property><property name="username" value="root"></property><property name="password" value="123456"></property>
</bean>

-
引入外部属性文件配置数据库连接池
-
- 创建外部属性文件,properties格式文件,写数据库信息
//properties的左边随便写,只是别名
prop.driverClass=com.mysql.cj.jdbc.Driver
prop.url=jdbc:mysql://localhost:3306/atguigu
prop.username=root
prop.password=123456
-
- 把外部properties属性文件引入到Spring配置文件中
-
-
- 引入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.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
-
-
- 在Spring配置文件使用标签引入外部属性文件
-
<!--直接去配置连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><!--<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property><property name="url" value="jdbc:mysql://localhost:3306/bjpowernode"></property><property name="username" value="root"></property><property name="password" value="root"></property>--><property name="driverClassName" value="${prop.driverClass}"></property><property name="url" value="${prop.url}"></property><property name="username" value="${prop.username}"></property><property name="password" value="${prop.password}"></property>
</bean><!--引入外部属性文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>

💖IOC操作Bean管理(基于注解方式)
注解的基本介绍
- 注解是代码特殊标记,格式:@注解名称(属性名称=属性值,属性名称=属性值)
- 使用注解,注解作用在类上面,方法上面,属性上面
- 使用注解目的:简化xml配置
- Spring针对Bean管理中创建对象提供注解
| @Component | 表示Spring容器中普通的组件 |
|---|---|
| @Service | 一般用于业务逻辑层或者service层 |
| @Controller | 一般用于外部层 |
| @Repository | 一般用于dao层或者持久层 |
- 特点:上面四个注解功能是一样的,都可以用来创建bean实例,没有什么区别,只不过为了让开发更加规范
基于注解方式实现对象创建
- 引入依赖 - 在你的Spring文件中的lib文件中的spring-aop

-
开启组件扫描
-
- 前提:引入名称空间context
<!--开启组件扫描1. 如果扫描多个包,多个包使用逗号隔开2. 扫描那个包的上层目录
-->
<!-- <context:component-scan base-package="com.zan.spring5.dao, com.zan.spring5.service"></context:component-scan> -->
<context:component-scan base-package="com.zan"></context:component-scan>

- 创建类,在类上面添加创建对象注解
//在注解里面的value属性值,可以省略不写
//不写默认值是类名称,把首字母小写,
//即我们这里是UserService,那默认就是userService
@Component(value = "userService")//里面是名字,跟<bean id="" class="">类似, id就是value
public class UserService {public void add() {System.out.println("service add.........");}
}


- 因此,通过注解,我们在xml中只需要开启组件扫描就可以了
开启组件扫描细节配置
<!--示例1use-default-filters="false":表示现在不使用默认的filter,使用自己配置的filtercontext:include-filter:表示设置要扫描哪些内容示例1解释:到com.zan中去扫描只带Controller的类
-->
<context:component-scan base-package="com.zan" use-default-filters="false"><context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan><!--示例2下面的配置是扫描包里的所有的内容context:exclude-filter:设置哪些内容不去扫描解释:到com.zan中扫描,但不扫描带Controller的类
-->
<context:component-scan base-package="com.zan"><context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

基于注解方式实现属性注入
-
@Autowired:根据属性类型进行自动装配
-
- 创建service和dao对象,在service和dao类上添加对象注解
- 在service注入dao对象,在service类添加dao类型属性,在属性上面使用注解
@Component(value = "userDaoImpl1")
public class UserDaoImpl implements UserDao{@Overridepublic void add() {System.out.println("dao add............");}
}//在注解里面的value属性值,可以省略不写
//不写默认值是类名称,把首字母小写,
//即我们这里是UserService,那默认就是userService
@Component(value = "userService")//里面是名字,跟<bean id="" class="">类似, id就是value
public class UserService {//定义dao类型属性//不需要添加set方法,因为在这里面已经封装了//只需要添加注入属性的注解就可以了@Autowired //根据类型进行自动注入private UserDao userDao;public void add() {System.out.println("service add.........");userDao.add();}
}

- @Qualifier:根据名称进行注入
- 注意:这个@Qualifier注解的使用,需要和@Autowired一起使用
package com.zan.spring5.service;import com.zan.spring5.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;import javax.annotation.Resource;//在注解里面的value属性值,可以省略不写
//不写默认值是类名称,把首字母小写,
//即我们这里是UserService,那默认就是userService
@Component(value = "userService")//里面是名字,跟<bean id="" class="">类似, id就是value
public class UserService {//定义dao类型属性//不需要添加set方法,因为在这里面已经封装了//只需要添加注入属性的注解就可以了@Autowired //根据类型进行自动注入@Qualifier(value = "userDaoImpl1") //根据名称注入private UserDao userDao;public void add() {System.out.println("service add.........");userDao.add();}
}
- 注意:dao类和service类的value必须一致


- @Resource:可以根据类型注入,也可以根据名称注入
// @Resource //根据类型进行注入
@Resource(name = "userDaoImpl1") //根据名称进行注入
private UserDao userDao2;
- 注意:注入Resource这个类是javax的扩展包中的annotation,因此Spring官方建议我们用Autowired和Qualifier
- @Value:注入普通类型属性
@Value(value = "abc")
private String name;public void add() {System.out.println("service add.........");
// userDao.add();userDao2.add();System.out.println(name);
}

完全注解开发(纯注解开发) - 不需要xml配置文件
- 创建配置类,用来替代xml配置文件
- 这个配置类,里面不写东西,相当于xml配置文件
package com.zan.spring5.config;import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;@Configuration //表示这个类作为配置类,来替代xml配置文件
@ComponentScan(basePackages = {"com.zan"}) //表示xml中的开启组件扫描
public class SpringConfig {}
- 测试
@Test
public void testService2() {//加载配置类ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);UserService userService = context.getBean("userService", UserService.class);userService.add();
}

相关文章:
Spring面试篇章——IOC
IOC概念和原理 IOC概念 IOC就是控制反射,把对象创建和对象之间的调用过程,交给Spring进行管理使用IOC的目的:降低耦合度 IOC底层原理 xml解析、工厂模式、反射 图解: 原始模式 耦合度太高了,即当dao改了…...
适合制造业的项目管理软件都有哪些?
项目管理软件涉及进度、预算成本、资源、开发、流程、质量、风险、工时、知识文档、商务等各个方面,是企业项目管理领域的重要辅助工具,能够帮助组织提高项目管理水平与质量,确保项目顺利进行。 一、 奥博思 PowerProject 项目管理系统 Pow…...
微应用(Micro-Applications)、微前端(Micro Frontend)、Qiankun 框架之间的区别和联系
简简单单 Online zuozuo: 简简单单 Online zuozuo 简简单单 Online zuozuo 简简单单 Online zuozuo 简简单单 Online zuozuo :本心、输入输出、结果 简简单单 Online zuozuo :联系我们:VX :tja6288 / EMAIL: 347969164@qq.com 文章目录 微应用(Micro-Applications)、微…...
String的底层构造
1.String类对象的构造(后面有每一个接口的实现) #define _CRT_SECURE_NO_WARNINGS 1 #pragma once #include<iostream> #include<assert.h> using namespace std;namespace bit {class string{public:typedef char* iterator;typedef const…...
Binder机制的原理
Binder机制是Android系统中用于进程间通信(IPC)的核心机制,它基于C/S(客户端-服务端)模型,允许不同进程间进行高效的通信和数据交换。以下是对Binder机制原理的详细解析: 1. Binder架构 Binde…...
JavaScript输出数据的方法?
在JavaScript中,输出数据有以下几种方法: 使用console.log()函数:使用console.log()函数可以将数据输出到浏览器的控制台,例如: console.log("Hello, World!");使用alert()函数:使用alert()函数…...
Redis学习笔记——第19章 事务
第19章 事务 19.1 事务的实现 19.1.1 事务开始 使用multi命令开启一个事务 通过修改客户端的flags字段为REDIS_MULTI 19.1.2 命令入队 当开启事务之后,exec、discard、watch、multi命令立即执行,而其他命令会放入一个队列中,并返回Queue…...
元太电磁膜SUDE-10S19MI-01X驱动适配
屏规格书: dts配置: 首先要确保CONFIG_I2C_HID宏打开,i2c-hid-core.c 文件才能编译进去代码。规格书vendor product 分别为0x2d1f 和0x0165 来区别,不至于影响到整体的hid其他设备。 i2c-hid-dev10 { compatible "hid-…...
C#数据类型 全局变量 类型转换方法(汇总)
1、C#和S7-1200PLC S7.NET通信 C#和S7-1200PLC S7.NET通信-CSDN博客文章浏览阅读98次。一步步建立一个C#项目(连续读取S7-1200PLC数据)_s7协议批量读取-CSDN博客这篇博客作为C#的基础系列,和大家分享如何一步步建立一个C#项目完成对S7-1200PLC数据的连续读取。首先…...
HCIP重修总笔记(中)
第八节 BGP基础 一、BGP产生背景 BGPBorder Gateway Protocol,边界网关协议)是一种用于自治系统间的动态路出协议,是一种外部网关协议。 自治系统AS:一组同一个管理机构进行管理,对外呈现统一选路策略的路由器的集合。 自治系统编号: …...
图片搜索网站,有大量高清图片,避免版权纠纷
一、简介 1、一个图片搜索网站,所有图片均遵循CC0协议,用户可以免费用于商业用途而无需标注来源。网站上有大量高清图片,基本可以满足用户的各种需求,同时避免了法律风险。提供强大的筛选功能,用户可以按图片方向、尺寸…...
设计学习笔记8:在设计模式中,状态模式和策略模式有什么区别,它们各自适用于什么场景?
基本介绍 状态模式(State Pattern)和策略模式(Strategy Pattern)都是行为型设计模式,它们用于处理不同的情景和需求,以下是它们的主要区别和适用场景: 状态模式(State Pattern&…...
Android 10.0 系统默认蓝牙打开状态栏显示蓝牙图标功能实现
1.前言 在10.0的系统rom定制化开发过程中,在默认系统中,打开蓝牙开关的时候不会状态栏不会显示蓝牙图标,而只有 蓝牙连接成功后会显示蓝牙图标,客户开发需要要求在蓝牙打开的时候在状态栏就显示蓝牙图标,接下来分析下 相关的状态栏图标显示流程,然后实现相关功能 2.系统…...
在git中如何忽略.vscode目录?
在Git中,如果你想忽略某个特定的文件或目录(比如.vscode目录),你可以通过以下步骤来实现: 创建或编辑.gitignore文件 在项目的根目录下,如果还没有.gitignore文件,你需要创建一个。如果已经有了…...
分布式系统
分布式系统是一种由多个相互连接的计算机组成的系统,这些计算机通过网络互相通信并协调行动来完成共同的任务。在分布式系统中,没有单一的物理实体可以控制整个系统;相反,各个节点(即计算机)独立运行&#…...
【Material-UI】Autocomplete 组件中的事件处理(Events)详解
文章目录 一、事件处理概述二、自定义按键行为代码详解 三、其他常见事件1. onChange 事件2. onInputChange 事件3. onFocus 和 onBlur 事件 四、实用场景1. 自定义提交行为2. 实现快捷键功能3. 动态提示 五、总结 在 Web 开发中,事件处理是实现用户交互的重要一环。…...
【51单片机仿真】基于51单片机设计的钟表定时闹钟系统仿真源码设计文档演示视频——完整资料下载
演示视频 设计内容 (1)使用 DS1302 结合字符型 LCD12864 显示器设计一个简易的定时闹钟 LCD 时钟。程序执行后 LCD 显示“00:00:00” (2)K1—设置现在的时间,年闪烁,再按 K1 键月闪…...
《刚刚问世》系列初窥篇-Java+Playwright自动化测试-7-元素基础定位方式-下篇 (详细教程)
软件测试微信群:https://bbs.csdn.net/topics/618423372 有兴趣的可以扫码加入 1.简介 上一篇主要是讲解我们日常工作中在使用Playwright进行元素定位的一些比较常用的基础定位方式的理论基础知识以及在什么情况下推荐使用。今天这一篇讲解和分享一下剩下部分的基…...
[Day 44] 區塊鏈與人工智能的聯動應用:理論、技術與實踐
生成对抗网络(Generative Adversarial Networks,GANs)是一种由Ian Goodfellow等人在2014年提出的深度学习模型,广泛用于图像生成、图像超分辨率、图像修复等领域。GAN由一个生成器(Generator)和一个判别器&…...
【Redis】 Redis 列表指令指南
这是我父亲 日记里的文字 这是他的生命 留下留下来的散文诗 几十年后 我看着泪流不止 可我的父亲已经 老得像一个影子 🎵 许飞《父亲写的散文诗》 Redis 是一个开源的内存数据库,支持多种数据结构,其中列表(…...
测试微信模版消息推送
进入“开发接口管理”--“公众平台测试账号”,无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息: 关注测试号:扫二维码关注测试号。 发送模版消息: import requests da…...
Vue记事本应用实现教程
文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...
Yolov8 目标检测蒸馏学习记录
yolov8系列模型蒸馏基本流程,代码下载:这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中,**知识蒸馏(Knowledge Distillation)**被广泛应用,作为提升模型…...
NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合
在汽车智能化的汹涌浪潮中,车辆不再仅仅是传统的交通工具,而是逐步演变为高度智能的移动终端。这一转变的核心支撑,来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒(T-Box)方案:NXP S32K146 与…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
在 Spring Boot 项目里,MYSQL中json类型字段使用
前言: 因为程序特殊需求导致,需要mysql数据库存储json类型数据,因此记录一下使用流程 1.java实体中新增字段 private List<User> users 2.增加mybatis-plus注解 TableField(typeHandler FastjsonTypeHandler.class) private Lis…...
STM32标准库-ADC数模转换器
文章目录 一、ADC1.1简介1. 2逐次逼近型ADC1.3ADC框图1.4ADC基本结构1.4.1 信号 “上车点”:输入模块(GPIO、温度、V_REFINT)1.4.2 信号 “调度站”:多路开关1.4.3 信号 “加工厂”:ADC 转换器(规则组 注入…...
高分辨率图像合成归一化流扩展
大家读完觉得有帮助记得关注和点赞!!! 1 摘要 我们提出了STARFlow,一种基于归一化流的可扩展生成模型,它在高分辨率图像合成方面取得了强大的性能。STARFlow的主要构建块是Transformer自回归流(TARFlow&am…...
