第四章:Spring上
第四章:Spring上
4.1:Spring简介
-  
Spring概述官网地址:
https://spring.io/。Spring是最受欢迎的企业级的java应用程序开发框架,数以百万的来自世界各地的开发人员使用Spring框架来创建性能好、易于测试、可重用的代码。Spring框架是一个开源的Java平台,它最初是由Rod Johnson编写的,并且于2003年5月首次在Apache 2.0许可下发布。Spring是轻量级的框架,其基础版本只有2MB左右的大小。Spring框架的核心特性是可以用于开发任何Java应用程序,但是在Java EE平台上构建web应用程序是需要扩展的。Spring框架的目标是使J2EE开发变得更容易使用,通过启用基于POJO编程模型来促进良好的编程实践。
 -  
Spring家族

 -  
Spring FrameworkSpring基础框架,可以视为Spring基础设施,基本上任何其他Spring项目都是以Spring Framework为基础的。-  
Spring Framework特性-  
非入侵式
 使用
Spring Framework开发应用程序是,Spring对应用程序本身的结构影响非常小。对领域模型可以做到零污染,对功能性组件也只需要使用几个简单的注解进行标记,完全不会破坏原有结构,反而能将组件结构进一步简化。这就使得基于Spring Framework开发应用程序时结构清晰、简洁优雅。 -  
控制反转
IOC————Inversion of Control,翻转资源获取方向。把自己创建资源、向环境索取资源变成环境资源准备好,我们享受资源注入。 -  
面向切面编程
AOP————Aspect Oriented Programming,在不修改资源代码的基础上增强代码功能。 -  
容器
Spring IOC是一个容器,因为它包含并且管理组件对象的生命周期。组件享受到了容器化的管理,替程序屏蔽了组件创建过程中的大量细节,极大的降低了使用门槛,大幅度提高了开发效率。 -  
组件化
Spring实现了使用简单的组件配置组合成一个复杂的应用。在Spring中可以使用XML和Java注解组合这些对象。这使得我们可以基于一个个功能明确、边界清晰的组件有条不紊的搭建超大型复杂应用系统。 -  
声明式
 很多以前需要编写代码才能实现的功能,现在只需要声明需求即可由框架代为实现。
 -  
一站式
 在
IOC和AOP的基础上可以整合各种企业应用的开源框架和优秀的第三方类库,而且Spring旗下的项目已经覆盖了广泛领域,很多方面的功能性需求可以在Spring Framework的基础上全部使用Spring来实现。 
 -  
 -  
Spring Framework五大功能模块功能模块 功能介绍 Core Container核心容器,在 Spring环境下使用任何功能都必须基于IOC容器AOP & Aspects面向切面编程 Testing提供了对 Junit或TestNG测试框架的整合Data Access/ Integration提供了对数据访问/集成的功能 Spring MVC提供了面向 Web应用程序的集成功能 
 -  
 
4.2:IOC
-  
IOC容器-  
IOC思想IOC:Inversion of Control,翻译过来是反转控制。-  
获取资源的传统方式
 在应用程序中的组件需要获取资源时,传统的方式是组件主动的从容器中获取所需要的资源,在这样的模式下开发人员往往需要知道在具体容器中特定资源的获取方式,增加了学习成本,同时降低了开发效率。
 -  
反转控制方式获取资源
 反转控制的思想完全颠覆了应用程序组件获取资源的传统方式:反转了资源的获取方向——改由容器主动的将资源推动给需要的组件,开发人员不需要知道容器是如何创建资源对象的,只需要提供接收资源的方式即可,极大的降低了学习成本,提高了开发的效率。这种行为也称为查找的被动形式。
 -  
DI
DI:Dependency Injection,翻译过来是依赖注入。
DI是IOC的另一种表述方式:即组件以一些预先定义好的方式接收来自于容器的资源注入,相对于IOC而言,这种表述更直接。 
IOC就是一种反转控制的思想,而DI是对IOC的一种具体实现。 -  
 -  
IOC容器在spring中的实现
Spring的IOC容器就是IOC思想的一个落地的产品实现。IOC容器中管理的组件也叫作bean。在创建bean之前,首先需要创建IOC容器。Spring提供了IOC容器的两种实现方式:-  
BeanFactory 这是
IOC容器的基本实现,是Spring内部使用的接口。面向Spring本身,不提供给开发人员使用。 -  
ApplicationContext
BeanFactory的子接口,提供了更多高级特性。面向Spring的使用者,几乎所有场合都使用ApplicationContext而不是底层的BeanFactory。 -  
ApplicationContext的主要实现类

 
类型名 简介 ClassPathXmlApplicationContext通过读取类路径下的 XML格式的配置文件创建IOC容器对象FileSystemXmlApplicationContext通过文件系统读取 XML格式的配置文件创建IOC容器对象ConfigurableApplicationContextApplicationContext的子接口,包含一些扩展方法refresh()和close(),让ApplicationContext具有启动、关闭和刷新上下文的能力WebApplicationContext专门为 Web应用准备,基于Web环境创建IOC容器对象,并将对象引入存入ServletContext域中 -  
 
 -  
 -  
基于
XML管理bean-  
实验一:入门案例
-  
创建模块
创建一个新的模块,
spring_helloworld_07。 -  
引入依赖
<packaging>jar</packaging><dependencies><!-- 基于Maven依赖传递性,导入spring-context依赖即可导入当前所需所有jar包 --><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.1</version></dependency><!-- junit测试 --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency> </dependencies> -  
创建类:
HelloWorldpackage com.wang.pojo;public class HelloWorld {public void sayHello() {System.out.println("Hello, spring");} } -  
创建
spring的配置文件

<!--bean: 配置一个bean对象,将对象交给IOC容器管理id: bean的唯一标识,不能重复class: 设置bean对象所对应的类型 --> <bean id="helloworld" class="com.wang.pojo.HelloWorld"></bean> -  
测试
@Test public void test() {// 获取IOC容器ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");// 获取IOC容器中的beanHelloWorld helloworld = (HelloWorld)ioc.getBean("helloworld");helloworld.sayHello(); } 
 -  
 
 -  
 

-  
实验二:获取
bean创建一个新的模块,
spring_ioc_xml_08,并引入spring_helloworld_07模块pom.xml的jar包。创建一个Student实体类。package com.wang.pojo;public class Student {private Integer sid;private String name;private Integer age;private String gender;// 如下省略空参构造、全参构造、get/set方法、toString方法 }<!-- 创建spring-ioc.xml配置文件配置一个bean对象 --> <bean id="studentOne" class="com.wang.pojo.Student"></bean>-  
根据
id获取由于
id属性指定了bean的唯一标识,所以根据bean标签的id属性可以精确获取到一个组件对象。 -  
根据类型获取
// 当根据类型获取bean时,要求IOC容器中指定类型的bean有且只能有一个// 若没有任何一个类型匹配的bean,此时抛出异常:NoSuchBeanDefinitionException// 若有多个类型匹配的bean,此时抛出异常:NoUniqueBeanDefinitionException @Test public void testIOC() {ApplicationContext ioc = new ClassPathXmlApplicationContext("spring-ioc.xml");Student student = ioc.getBean(Student.class);System.out.println(student); } -  
根据
id和类型// 如果组件实现了接口,根据接口类型可以获取bean,但是要求bean唯一 @Test public void testIOC() {ApplicationContext ioc = new ClassPathXmlApplicationContext("spring-ioc.xml");Student student = ioc.getBean("studentOne", Student.class);// 其中Student实现了Perso接口,且只有唯一的Student类实现了Person接口// Person person = ioc.getBean(Person.class);System.out.println(person); } 根据类型来获取
bean时,在满足bean唯一性的前提下,其实只是看:对象 instanceof 指定的类型的返回结果,只要返回结果为true就可以认定为为和类型匹配,能够获取到。 
 -  
 -  
实验三:依赖注入值
setter注入<bean id="studentTwo" class="com.wang.pojo.Student"><!--property: 通过成员变量的set方法进行赋值name:设置需要赋值的属性名(和set方法有关)value:设置为属性所赋的值--><property name="sid" value="1001"></property><property name="name" value="张三"></property><property name="age" value="23"></property><property name="gender" value="男"></property> </bean>@Test public void testDI() {ApplicationContext ioc = new ClassPathXmlApplicationContext("spring-ioc.xml");Student student = ioc.getBean("studentTwo", Student.class);System.out.println(student); } -  
实验四:依赖注入之构造器注入
<!-- constructor-arg标签属性name: 指定参数名index: 指定参数所在位置的索引(从0开始) --> <bean id="studentThree" class="com.wang.pojo.Student"><constructor-arg value="1002"></constructor-arg><constructor-arg value="李四"></constructor-arg><constructor-arg value="女"></constructor-arg><constructor-arg value="24"></constructor-arg> </bean>@Test public void testDI() {ApplicationContext ioc = new ClassPathXmlApplicationContext("spring-ioc.xml");Student student = ioc.getBean("studentThree", Student.class);System.out.println(student); } -  
实验五:特殊值处理
-  
字面量赋值
<!-- 使用value属性给bean的属性赋值时,Spring会把value属性的值看做字面量 --> <property name="name" value="张三"></property> -  
null值<property name="gender"><null/></property> -  
xml实体<!-- value属性值为<王五> --> <property name="name" value="<王五>"></property> -  
CDATA节<!--CDATA中的C代表Character,是文本、字符的含义、CDATA就表示纯文本数据。XML解析器看到CDATA节就知道这里是纯文本,就不会当作XML标签或属性来解析,所以CDATA节中写什么符号都随意 --> <property name="name"><value><![CDATA[<王五>]]></value> </property> 
 -  
 -  
实验六:为类类型属性值赋值
-  
创建一个
Clazz类package com.wang.pojo;public class Clazz {private Integer cid;private String cname;// 如下省略空参构造、全参构造、get/set方法、toString方法 } -  
在
Stduent中添加一个属性private Clazz clazz; -  
方式一:引用外部以声明的
bean<bean id="studentFive" class="com.wang.pojo.Student"><property name="sid" value="1004"></property><property name="name" value="赵六"></property><property name="age" value="26"></property><property name="gender" value="男"></property><!-- ref:引用IOC容器中的某个bean的id --><property name="clazz" ref="clazzOne"></property> </bean><bean id="clazzOne" class="com.wang.pojo.Clazz"><property name="cid" value="1111"></property><property name="cname" value="最强王者班"></property> </bean> -  
方式二:级联属性赋值
<bean id="studentFive" class="com.wang.pojo.Student"><property name="sid" value="1004"></property><property name="name" value="赵六"></property><property name="age" value="26"></property><property name="gender" value="男"></property><!-- ref:引用IOC容器中的某个bean的id --><property name="clazz" ref="clazzOne"></property><!-- 级联的方式,要保证提前为clazz属性赋值或者实例化 --><property name="clazz.cid" value="2222"></property><property name="clazz.cname" value="远大前程班"></property> </bean> -  
方式三:内部
bean<bean id="studentFive" class="com.wang.pojo.Student"><property name="sid" value="1004"></property><property name="name" value="赵六"></property><property name="age" value="26"></property><property name="gender" value="男"></property><property name="clazz"><!-- 内部bean,只能在当前bean的内部使用,不能直接通过IOC容器获取 --><bean id="clazzInner" class="com.wang.pojo.Clazz"><property name="cid" value="2222"></property><property name="cname" value="远大前程班"></property></bean></property> </bean> 
 -  
 -  
实验七:为数组类型属性赋值
-  
在
Student类添加一个属性private String[] hobby; -  
配置
bean<bean id="studentFive" class="com.wang.pojo.Student"><property name="sid" value="1004"></property><property name="name" value="赵六"></property><property name="age" value="26"></property><property name="gender" value="男"></property><property name="hobby"><array><value>抽烟</value><value>喝酒</value><value>烫头</value></array></property> </bean> 
 -  
 -  
实验八:为集合类型属性赋值
-  
为
List集合类型属性赋值-  
在
Clazz类中添加一个students属性private List<Student> students; -  
方式一:在内部配置
bean<bean id="clazzOne" class="com.wang.pojo.Clazz"><property name="cid" value="1111"></property><property name="cname" value="最强王者班"></property><property name="students"><list><ref bean="studentOne"></ref><ref bean="studentTwo"></ref><ref bean="studentThree"></ref></list></property> </bean> -  
方式二:在外部配置
bean<bean id="clazzOne" class="com.wang.pojo.Clazz"><property name="cid" value="1111"></property><property name="cname" value="最强王者班"></property><property name="students" ref="studentList"></property> </bean><!-- 配置一个集合类型额bean,需要使用util的约束 --> <util:list id="studentList"><ref bean="studentOne"></ref><ref bean="studentTwo"></ref><ref bean="studentThree"></ref> </util:list> 
 -  
 -  
为
Map集合类型属性赋值-  
创建
Teacher类package com.wang.pojo;public class Teacher {private Integer tid;private String tname; } -  
在
Student类中添加一个属性private Map<String, Teacher> teacherMap; -  
方式一:在内部配置
bean<bean id="studentFive" class="com.wang.pojo.Student"><property name="sid" value="1004"></property><property name="name" value="赵六"></property><property name="age" value="26"></property><property name="gender" value="男"></property><property name="teacherMap"><map><entry key="10086" value-ref="teacherOne"></entry><entry key="10010" value-ref="teacherTwo"></entry></map></property> </bean><bean id="teacherOne" class="com.wang.pojo.Teacher"><property name="tid" value="10086"></property><property name="tname" value="大宝"></property> </bean> <bean id="teacherTwo" class="com.wang.pojo.Teacher"><property name="tid" value="10010"></property><property name="tname" value="小宝"></property> </bean> -  
方式二:在外部配置
bean<bean id="studentFive" class="com.wang.pojo.Student"><property name="sid" value="1004"></property><property name="name" value="赵六"></property><property name="age" value="26"></property><property name="gender" value="男"></property><property name="teacherMap" ref="studentMap"></property> </bean><util:map id="studentMap"><entry key="10086" value-ref="teacherOne"></entry><entry key="10010" value-ref="teacherTwo"></entry> </util:map> 
 -  
 
 -  
 -  
实验九:
p命名空间 引入
p命名空间后,可以通过以下方式为bean的各个属性赋值。<bean id="studentSix" class="com.wang.pojo.Student"p:sid="1005" p:name="小明" p:teacherMap-ref="studentMap"></bean> -  
实验十:引入外部属性文件
-  
加入依赖
<!-- MySQL驱动 --> <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.16</version> </dependency> <!-- 数据源 --> <dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.0.31</version> </dependency> -  
创建外部文件
jdbc.propertiesjdbc.driver=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC jdbc.username=root jdbc.password=abc123 -  
创建
spring-datasource.xml并引入外部文件<!-- 引入jdbc.properties, 之后可以通过${key}的方式访问value--> <context:property-placeholder location="jdbc.properties" ></context:property-placeholder> -  
配置
bean<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="${jdbc.driver}"></property><property name="url" value="${jdbc.url}"></property><property name="username" value="${jdbc.username}"></property><property name="password" value="${jdbc.password}"></property> </bean> -  
测试,新建
DataSourceTest.java文件@Test public void testDataSource() throws SQLException {ApplicationContext ioc = new ClassPathXmlApplicationContext("spring-datasource.xml");DruidDataSource dataSource = ioc.getBean(DruidDataSource.class);System.out.println(dataSource.getConnection()); } 
 -  
 -  
实验十一:
bean的作用域在
Spring中可以通过配置bean标签的scope属性来指定bean的作用域范围,各取值含义参加下表:取值 含义 创建对象的时机 singleton(默认)在 IOC容器中,这个bean的对象始终为单实例IOC容器初始化时prototype这个 bean在IOC容器中有多个实例获取 bean时如果是在
WebApplicationContext环境下还会有另外两个作用域(但不常用):取值 含义 request在一个请求范围内有效 session在一个会话范围内有效 <!-- 创建spring-scope.xml配置文件配置一个bean对象 --> <bean id="student" class="com.wang.pojo.Student" scope="prototype"><property name="sid" value="1001"></property><property name="name" value="张三"></property> </bean>@Test public void testScope() {ApplicationContext ioc = new ClassPathXmlApplicationContext("spring-scope.xml");Student student1 = ioc.getBean(Student.class);Student student2 = ioc.getBean(Student.class);System.out.println(student1 == student2); // false } -  
实验十二:
bean生命周期-  
具体的生命周期过程
- 实例化:
bean对象创建(调用无参构造器)。 - 依赖注入:给
bean对象设置属性。 - 后置处理器的
postProcessBeforeInitialization:bean对象初始化之前操作(由bean的后置处理器负责)。 - 初始化,需要通过
bean的init-method:对象的初始化(需要配置bean时指定初始化方法)。 - 后置处理器的
postProcessAfterInitialization:bean对象初始化之后操作(由bean的后置处理器负责)。 IOC容器关闭时销毁,需要通过bean的destroy-method属性指定销毁的方法:bean对象销毁(需在配置bean时指定销毁方法)。
 - 实例化:
 -  
注意:
- 若
bean的作用域为单例时,生命周期的前三个步骤会在获取IOC容器时执行。 - 若
bean的作用域为多例时,生命周期的前三个步骤会在获取bean时执行。 
 - 若
 -  
创建
User类package com.wang.pojo;public class User {private Integer id;private String username;private String password;private Integer age;// 如下省略空参构造、全参构造、get/set方法、toString方法// 空参构造和这一个set方法按下面方式改动即可,其他的不变public User() {System.out.println("生命周期1:实例化");}public void setId(Integer id) {System.out.println("生命周期2:依赖注入");this.id = id;}public void initMethod() {System.out.println("生命周期3:初始化");}public void destroyMethod() {System.out.println("生命周期4:销毁");} } -  
创建
spring-lifecyc.xml配置文件配置bean对象<bean id="user" class="com.wang.pojo.User" init-method="initMethod" destroy-method="destroyMethod"><property name="id" value="1"></property><property name="username" value="admin"></property><property name="password" value="123456"></property><property name="age" value="23"></property> </bean> -  
bean的后置处理器
bean的后置处理器会在生命周期的初始化前后添加额外的操作,需要实现BeanPostProcessor接口,且配置到IOC容器中,需要注意的是,bean后置处理器不是单独针对某一个bean生效,而是针对IOC容器中所有bean都会执行。package com.wang.process;public class MyBeanPostProcessor implements BeanPostProcessor {// 此方法在bean的生命周期初始化之前执行@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println("MyBeanPostProcessor--->后置处理器postProcessBeforeInitialization");return bean;}// 此方法在bean的生命周期初始化之后执行@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("MyBeanPostProcessor--->前置处理器postProcessAfterInitialization");return bean;} }<bean id="myBeanPostProcessor" class="com.wang.process.MyBeanPostProcessor"></bean> -  
测试
@Test public void test() {ConfigurableApplicationContext ioc = new ClassPathXmlApplicationContext("spring-lifecycle.xml");User user = ioc.getBean(User.class);System.out.println(user);ioc.close(); } 
 -  
 -  
实验十三:
FactoryBean-  
简介
FactoryBean是spring提供的一种整合第三方框架的常用机制。和普通的bean不同,配置一个FactoryBean类型的bean,在获取bean的时候得到的并不是class属性中配置的这个类的对象,而是getObject()方法的返回值。通过这种机制,Spring可以帮我们把复杂组件创建的详细过程和繁琐细节都屏蔽起来,只把最简洁的使用界面展示给我们。package org.springframework.beans.factory;public interface FactoryBean<T> {String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";@NullableT getObject() throws Exception;@NullableClass<?> getObjectType();default boolean isSingleton() {return true;} } -  
创建类
UserFactoryBeanpackage com.wang.factory;public class UserFactoryBean implements FactoryBean<User> {@Overridepublic User getObject() throws Exception {return new User();}@Overridepublic Class<?> getObjectType() {return User.class;} } -  
配置
bean<bean class="com.wang.factory.UserFactoryBean"></bean> -  
测试
@Test public void testFactoryBean() {ApplicationContext ioc = new ClassPathXmlApplicationContext("spring-factory.xml");User user = ioc.getBean(User.class);System.out.println(user); } 
 -  
 -  
实验十四:基于
xml的自动装配自动装配:根据指定的策略,在
IOC容器中匹配某一个bean,自动为指定的bean中所依赖的类类型或接口类型属性赋值。-  
场景模拟
-  
dao层:package com.wang.dao;public interface UserDao {void saveUser(); }package com.wang.dao.impl;public class UserDaoImpl implements UserDao {@Overridepublic void saveUser() {System.out.println("保存成功");} } -  
service层:package com.wang.service;public interface UserService {void saveUser(); }package com.wang.service.impl;public class UserServiceImpl implements UserService {private UserDao userDao;public UserDao getUserDao() {return userDao;}public void setUserDao(UserDao userDao) {this.userDao = userDao;}@Overridepublic void saveUser() {userDao.saveUser();} } -  
controller层:package com.wang.controller;public class UserController{private UserService userService;public void setUserService(UserService userService){this.userService = userService;}public void saveUser() {userService.saveUser();} } -  
配置
bean:手动配置<!-- 创建spring-autowire-xml.xml配置文件配置bean对象 --> <bean id="userController" class="com.wang.controller.UserController"><property name="userService" ref="userService"></property> </bean><bean id="userService" class="com.wang.service.impl.UserServiceImpl"><property name="userDao" ref="userDao"></property> </bean><bean id="userDao" class="com.wang.dao.impl.UserDaoImpl"></bean> -  
测试
@Test public void testAutowire() {ApplicationContext ioc = new ClassPathXmlApplicationContext("spring-autowire-xml.xml");UserController userController = ioc.getBean(UserController.class);userController.saveUser(); } 
 -  
 -  
使用
byType方式自动装配<!--自动装配的策略:1. no, default: 表示不装配,即bean中的属性不会自动匹配某个bean为属性值,此时属性使用默认值2. byType:根据要赋值的属性的类型,在IOC容器中匹配某个bean,为属性赋值注意:1. 若通过类型没有找到任何一个类型匹配的bean,此时不装配,属性使用默认值。2. 若通过类型找到了多个类型匹配的bean,此时会抛出异常: NoUniqueBeanDefinitionException。 --> <bean id="userController" class="com.wang.controller.UserController" autowire="byType"></bean> <bean id="userService" class="com.wang.service.impl.UserServiceImpl" autowire="byType"></bean> <bean id="userDao" class="com.wang.dao.impl.UserDaoImpl"></bean> -  
使用
byName方式自动装配<!--byName:将要赋值的属性的属性名作为bean的id在IOC容器中匹配某个bean,为属性赋值。当类型匹配的bean有多个时,此时可以使用byName实现自动装配 --> <bean id="userController" class="com.wang.controller.UserController" autowire="byName"></bean> <bean id="userService" class="com.wang.service.impl.UserServiceImpl" autowire="byName"></bean> <bean id="userDao" class="com.wang.dao.impl.UserDaoImpl"></bean> 
 -  
 
-  
基于注解管理
bean-  
实验一:标记与扫苗
-  
注解
 和
XML配置文件一样,注解本身并不能执行,注解本身仅仅只是做一个标记,具体的功能是框架检测到注解标记的位置,然后针对这个位置按照注解标记的功能来执行具体操作。 本质上:所有一切的操作都是
Java代码来完成的,XML和注解只是告诉框架中的Java代码如何执行。 -  
扫描
Spring为了知道程序员在哪些地方标记了什么注解,就需要通过扫描的方式,来进行检测。然后跟注解进行后续操作。 -  
新建模块
 创建一个新的模块,
spring_ioc_annotation_09,并引入下面的jar包。<packaging>jar</packaging><dependencies><!-- 基于Maven依赖传递性,导入spring-context依赖即可导入当前所需所有jar包 --><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.1</version></dependency><!-- junit测试 --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency> </dependencies> -  
标识组件的常用注解
@Component:将类标识为普通组件。@Repository:将类标识为持久层组件。@Service:将类标识为业务层组件。@Controller:将类标识为持久层组件。
 通过源码我们得知:
@Repository、@Service、@Controller这三个注解只是在@Component注解的基础上起了三个新名字。对于Spring使用IOC容器管理这些组件来说没有区别。所以@Repository、@Service、@Controller这三个注解只是给开发人员看的,让我们能够便于分辨组件的作用。 -  
创建组件
-  
dao层:package com.wang.dao;public interface UserDao { }package com.wang.dao.impl;@Repository public class UserDaoImpl implements UserDao { } -  
service层:package com.wang.service;public interface UserService { }package com.wang.service.impl;@Service public class UserServiceImpl implements UserService { } -  
controller层:package com.wang.controller;@Controller public class UserController { } 
 -  
 -  
扫描组件
-  
情况一:最基本的扫描方式
<!-- 创建spring-ioc-annotation.xml配置文件--> <context:component-scan base-package="com.wang"></context:component-scan> -  
情况二:指定要排除的组件
<!--context:exclude-filter: 排除扫描type: 设置排除扫描的方式annotation: 根据注解的类型进行排除, expression需要设置排除的注解的全类名assignable: 根据类的类型进行排除, expression需要设置排除的类的全类名 --> <context:component-scan base-package="com.wang" use-default-filters="false"><context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> <!-- <context:exclude-filter type="assignable" expression="com.wang.controller.UserController"/>--> </context:component-scan> -  
情况三:仅扫描指定组件
<!--context:include-filter: 包含扫描注意: 需要在context:component-scan标签中设置use-default-filters="false"use-default-filters: 默认为true, 设置的包下所有的类是否都需要扫描 --> <context:component-scan base-package="com.wang" use-default-filters="false"><context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> 
 -  
 -  
测试
@Test public void test() {ApplicationContext ioc = new ClassPathXmlApplicationContext("spring-ioc-annotation.xml");UserController userController = ioc.getBean(UserController.class);System.out.println(userController);UserService userService = ioc.getBean(UserService.class);System.out.println(userService);UserDao userDao = ioc.getBean(UserDao.class);System.out.println(userDao); } -  
组件所对应的
bean的id 通过注解+扫描所配置的
bean的id,默认值为类的小驼峰,即类名的首字母为小写的结果。可以通过标识组件的注解的value属性值设置bean的自定义的id。 
 -  
 -  
实验二:基于注解的自动装配
-  
场景模拟
-  
dao层:void saveUse();@Override public void saveUse() {System.out.println("保存成功"); } -  
service层:void saveUser();@Autowired private UserDao userDao;@Override public void saveUser() {userDao.saveUse(); } -  
controller层:@Autowired private UserService userService;// @Autowired // public UserController(UserService userService) { // this.userService = userService; // }// @Autowired // public void setUserService(UserService userService) { // this.userService = userService; // }public void saveUser() {userService.saveUser(); } 
 -  
 -  
Autowired注解能够标识的位置- 标识在成员变量上,此时不需要设置成员变量的
set方法。 - 标识在
set方法上。 - 标识在为当前成员变量赋值的有参构造上。
 
 - 标识在成员变量上,此时不需要设置成员变量的
 -  
Autowired注解的原理- 默认通过
byType的方式,在IOC容器中通过类型匹配某个bean为属性赋值。 - 若有多个类型匹配的
bean,此时会自动转换为byName的方式实现自动装配的效果。 - 若
byType和byName的方式都无法实现自动装配,即IOC容器中有多个类型匹配的bean且这些bean的id要赋值的属性的属性名都不一致,此时抛异常:NoUniqueBeanDefinitionException。 - 此时可以在要赋值的属性上,添加一个注解
@Qualifier,通过该注解的value属性值,指定某个bean的id,将这个bean为属性赋值。 
 - 默认通过
 -  
Autowired注解的注意事项 若
IOC容器中没有任何一个类型匹配的bean,此时抛出异常:NoSuchBeanDefinitionException。在@Autowired注解中有个属性required,默认值为true,要求必须完成自动装配,可以将required设置为false,此时能装配则装配,无法装配则使用属性的默认值。 
 -  
 
 -  
 
相关文章:
第四章:Spring上
第四章:Spring上 4.1:Spring简介 Spring概述 官网地址:https://spring.io/。 Spring是最受欢迎的企业级的java应用程序开发框架,数以百万的来自世界各地的开发人员使用Spring框架来创建性能好、易于测试、可重用的代码。Spring框…...
【时频分析,非线性中频】非线性STFT在瞬时频率估计中的应用(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
MTK平台关机流程和原因(二)
(1)ShutdownThread 从上一篇可以看到,最终会调用此类的shutdown以及reboot等函数,我们来看一下这些函数的实现。 (A)被调用函数 //frameworks/base/services/core/java/com/android/server/power/Shutdo…...
【Python】pyqt6入门到入土系列,非常详细...
前言 嗨喽,大家好呀~这里是爱看美女的茜茜呐 一、什么是PyQt6? 简单介绍一下PyQt6 1、基础简介 PyQt6 Digia 公司的 Qt 程序的 Python 中间件。Qt库是最强大的GUI库之一。 PyQt6的官网:www.riverbankcomputing.co.uk/news。 PyQt6是由Riverbank Co…...
TCP socket编程
一、服务端代码 #encoding utf -8 #导入socket库 from socket import * #等待客户端来连接,主机地址为0.0.0.0表示绑定本机所有网络接口ip地址 IP 0.0.0.0 #端口号 PORT 50000 #定义一次从socket缓存区最多读入512个字节数据 BUFLEN 512 #实例化一个socket编程…...
HTTP——一、了解Web及网络基础
HTTP 一、使用HTTP协议访问Web二、HTTP的诞生1、为知识共享而规划Web2、Web成长时代3、驻足不前的HTTP 三、网络基础TCP/IP1、TCP/IP协议族2、TCP/IP的分层管理3、TCP/IP 通信传输流 四、与HTTP关系密切的协议:IP、TCP和DNS1、负责传输的 IP 协议2、确保可靠性的TCP…...
[论文笔记] chatgpt系列 2.6 DeepSpeed-chat 数据集
一、FT数据集 & Reward model数据集 Deepspeed-chat 源代码的数据集: Dahoas/rm-static: 这是一个用于强化学习的静态环境数据集,包含了一个机器人在一个固定环境中的运动轨迹。该数据集旨在用于评估强化学习算法在静态环境下的表现。 Dahoas/full-hh-rlhf: 这是一个用于…...
探究SAM和眼球追踪技术在自动医学图像分割的应用(2023+GazeSAM: What You See is What You Segment)
摘要: 本研究探讨眼动追踪技术与SAM的潜力,以设计一个协同的人机交互系统,自动化医学图像分割。提出了GazeSAM系统,使放射科医生能够在图像诊断过程中通过简单地查看感兴趣的区域来收集分割掩模。该系统跟踪放射科医生的眼球运动…...
excle中的条件求和SUMIF
问题:将每一行中红色文字的前一个值累计求和到境外总数这一列 使用的公式 自制单元格的格式计算公式:ctrlf3打开格式管理,创建如下公式,其中24是表示获取文字颜色 由于sumif只能直接与第二参数条件比较,所以先使用IF(公…...
python-网络爬虫.Request
Request python中requests库使用方法详解: 一简介: Requests 是Python语言编写,基于urllib, 采用Apache2 Licensed开源协议的 HTTP 库。 与urllib相比,Requests更加方便,处理URL资源特别流畅。 可以节约我…...
时序预测 | MATLAB实现GRNN广义回归神经网络时间序列预测(多指标,多图)
时序预测 | MATLAB实现GRNN广义回归神经网络时间序列预测(多指标,多图) 目录 时序预测 | MATLAB实现GRNN广义回归神经网络时间序列预测(多指标,多图)效果一览基本介绍程序设计参考资料效果一览 基本介绍 1.MATLAB实现GRNN广义回归神经网络时间序列预测(完整源码和数据) …...
如何看待低级爬虫与高级爬虫?
爬虫之所以分为高级和低级,主要是基于其功能、复杂性和灵活性的差异。根据我总结大概有下面几点原因: 功能和复杂性:高级爬虫通常提供更多功能和扩展性,包括处理复杂页面结构、模拟用户操作、解析和清洗数据等。它们解决了开发者…...
3.分支与循环
一、分支结构 1.概念 一个 CPP 程序默认是按照代码书写顺序,从上到下依次执行下来的。但是,有时我们需要选择性的执行某些语句,来实现更加复杂的逻辑,这时候就需要分支结构语句的功能来实现。选择合适的分支语句可以显著提高程序…...
面试之多线程案例(四)
1.单例模式 单例模式是指在内存中只会创建且仅创建一次对象的设计模式。在程序中多次使用同一个对象且作用相同时,为了防止频繁地创建对象使得内存飙升,单例模式可以让程序仅在内存中创建一个对象,让所有需要调用的地方都共享这一单例对象。…...
抄写Linux源码(Day1:获取并运行 Linux0.11)
Day1:获取并运行 Linux0.11 参考资料:https://zhuanlan.zhihu.com/p/438577225 这是我参考的一个别人写的 Linux0.11 解读:https://github.com/dibingfa/flash-linux0.11-talk 我获取 Linux-0.11 源码的链接:https://github.com/…...
大数据_Hadoop_Parquet数据格式详解
之前有面试官问到了parquet的数据格式,下面对这种格式做一个详细的解读。 参考链接 : 列存储格式Parquet浅析 - 简书 Parquet 文件结构与优势_parquet文件_KK架构的博客-CSDN博客 Parquet文件格式解析_parquet.block.size_davidfantasy的博客-CSDN博…...
Docker的安装和部署
目录 一、Docker的安装部署 (1)关闭防火墙 (2)关闭selinux (3)安装docker引擎 (4)启动docker (5)设置docker自启动 (6)测试doc…...
FPGA项目实现:秒表设计
文章目录 项目要求项目设计 项目要求 设计一个时钟秒表,共六个数码管,前两位显示分钟,中间两位显示时间秒,后两位显示毫秒的高两位,可以通过按键来开始、暂停以及重新开始秒表的计数。 项目设计 为完成此项目共设计…...
Postgresql源码(109)并行框架实例与分析
1 PostgreSQL并行参数 系统参数 系统总worker限制:max_worker_processes 默认8 系统总并发限制:max_parallel_workers 默认8 单Query限制:max_parallel_workers_per_gather 默认2 表参数限制:parallel_workers alter table tbl …...
ES派生类的prototype方法中,不能访问super的解决方案
1 下面的B.prototype.compile方法中,无法访问super class A {compile() {console.log(A)} }class B extends A {compile() {super.compile()console.log(B)} }B.prototype.compile function() {super.compile() // 报错,不可以在此处使用superconsole.…...
uniapp 对接腾讯云IM群组成员管理(增删改查)
UniApp 实战:腾讯云IM群组成员管理(增删改查) 一、前言 在社交类App开发中,群组成员管理是核心功能之一。本文将基于UniApp框架,结合腾讯云IM SDK,详细讲解如何实现群组成员的增删改查全流程。 权限校验…...
Java 语言特性(面试系列2)
一、SQL 基础 1. 复杂查询 (1)连接查询(JOIN) 内连接(INNER JOIN):返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...
2025年能源电力系统与流体力学国际会议 (EPSFD 2025)
2025年能源电力系统与流体力学国际会议(EPSFD 2025)将于本年度在美丽的杭州盛大召开。作为全球能源、电力系统以及流体力学领域的顶级盛会,EPSFD 2025旨在为来自世界各地的科学家、工程师和研究人员提供一个展示最新研究成果、分享实践经验及…...
Keil 中设置 STM32 Flash 和 RAM 地址详解
文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...
从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...
微信小程序云开发平台MySQL的连接方式
注:微信小程序云开发平台指的是腾讯云开发 先给结论:微信小程序云开发平台的MySQL,无法通过获取数据库连接信息的方式进行连接,连接只能通过云开发的SDK连接,具体要参考官方文档: 为什么? 因为…...
基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解
JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用,结合SQLite数据库实现联系人管理功能,并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能,同时可以最小化到系统…...
Chrome 浏览器前端与客户端双向通信实战
Chrome 前端(即页面 JS / Web UI)与客户端(C 后端)的交互机制,是 Chromium 架构中非常核心的一环。下面我将按常见场景,从通道、流程、技术栈几个角度做一套完整的分析,特别适合你这种在分析和改…...
Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement
Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement 1. LAB环境2. L2公告策略2.1 部署Death Star2.2 访问服务2.3 部署L2公告策略2.4 服务宣告 3. 可视化 ARP 流量3.1 部署新服务3.2 准备可视化3.3 再次请求 4. 自动IPAM4.1 IPAM Pool4.2 …...
Linux安全加固:从攻防视角构建系统免疫
Linux安全加固:从攻防视角构建系统免疫 构建坚不可摧的数字堡垒 引言:攻防对抗的新纪元 在日益复杂的网络威胁环境中,Linux系统安全已从被动防御转向主动免疫。2023年全球网络安全报告显示,高级持续性威胁(APT)攻击同比增长65%,平均入侵停留时间缩短至48小时。本章将从…...
