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 是一个开源的内存数据库,支持多种数据结构,其中列表(…...

设计测试用例的具体方法
一.等价类 等价类分为: 1.有效等价类 [6~15] 2.无效等价类 :小于6位,大于15位(不在数据范围内) 组合规则: 有效等价类组合的时候,尽可能一条测试用例尽可能多的覆盖有效等价类 无效等价类组合的时候,一条测试点,之恶能覆盖一个无效等价类 二.边界值 1.上点,离点,内点 上…...

GPT-4o mini(假设模型)概览
开篇背景: 近年来,随着计算能力的提升和大数据的积累,大型语言模型(LLMs)如GPT系列取得了显著进展。这些模型不仅能够理解复杂的自然语言文本,还能生成流畅、连贯的回复,甚至展现出一定程度的创…...

抽象代数精解【9】
文章目录 置换密码密码体制加解密过程置换置换运算定义置换运算的例子集合与置换置换规则两行表示法轮换表示法置换运算的结果置换的性质注意事项 分组加解密 理论基础1. 准备工作2. 置换过程3. 置换密码的具体实现方式4. 安全性分析5. 置换密码的应用代换密码代换密码的工作原…...

熟悉简单测试面经
SQL语句中增、删、查、改的关键字 MySQL中SQL语句删除语句有哪些?区别是啥。 “”和equals的区别 “String s "1"”与“String s new String("1")”中的s一样吗? StringBuilder与StringBuffer的区别 洗牌问题 HTTP、HTTPS、U…...

IoTDB 入门教程 实战篇④——C#示例(开源)
文章目录 一、前文二、新建C#项目三、NuGet安装四、示例源码五、查询数据六、参考 一、前文 IoTDB入门教程——导读 本文详细阐述了如何通过一个C#项目成功连接到IoTDB时序数据库,进而展示了如何向该数据库高效地写入数据以及执行精确的数据查询操作。 此示例旨在为…...

STL-vector容器
目录 一、常见接口 1.1 构造函数 1.2 访问与遍历 1.3 容量操作 1.4 增删查改 二、模拟实现 2.1 迭代器失效 2.2 源代码 一、常见接口 vector数据结构实际上是顺序表 详细解释与使用请参见官方网站:vector - C Reference (cplusplus.com) 1.1 构造函数 函…...

python字符串与变量名互相转换,字典,list操作
locals是python的内置函数,他可以以字典的方式去访问局部和全局变量 vars()本函数是实现返回对象object的属性和属性值的字典对象 eval()将字符串str当成有效的表达式来求值并返回计算结果 #!/usr/bin/python3 #-*- coding uft-8 -*- guo 666 str1 "guo&qu…...

企业及园区电力能源管理系统方案
概述 面对中小型的用能集团、园区能耗监测分析等场景需求,拓扑未来公司推出标准化的企业及园区电力能源管理系统方案,力求高效高质地为目标客户提供高效部署、轻松运维的本地化能源管理解决方案。 本方案以软硬件一体的方式,集成了标准电力监…...

5.3 需求分析
需求分析 软件需求定义分类练习题 需求工程需求获取练习题 需求分析状态转化图数据流图DFD顶层数据流图0层数据流图1层数据流图 练习题 需求规约需求定义方法 需求验证需求管理版本控制需求跟踪变更控制练习题 考试大概3分 软件需求 定义 软件需求:是指用户对目标…...

【C++】list介绍以及模拟实现(超级详细)
欢迎来到我的Blog,点击关注哦💕 list的介绍和模拟实现 前言list介绍标准库容器 std::list 与 std::vector 的优缺点缺点 list的基本操作构造函数list iteratorlist capcacitylist modify list模拟实现存贮结构(双向带头循环)itera…...