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 是一个开源的内存数据库,支持多种数据结构,其中列表(…...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

Debian系统简介
目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版ÿ…...
多场景 OkHttpClient 管理器 - Android 网络通信解决方案
下面是一个完整的 Android 实现,展示如何创建和管理多个 OkHttpClient 实例,分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...
连锁超市冷库节能解决方案:如何实现超市降本增效
在连锁超市冷库运营中,高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术,实现年省电费15%-60%,且不改动原有装备、安装快捷、…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例
文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

苍穹外卖--缓存菜品
1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据,减少数据库查询操作。 缓存逻辑分析: ①每个分类下的菜品保持一份缓存数据…...

tree 树组件大数据卡顿问题优化
问题背景 项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术&…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
比较数据迁移后MySQL数据库和OceanBase数据仓库中的表
设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...