目录
Spring核心功能IoC:
概述:
什么是控制反转:
IoC容器:
IOC的技术实现 :
Spring的第一个程序:
第一步:创建一个Maven工程
第二步:创建一个接口
第三步:创建接口实现类
第四步:在resource资源文件目录下创建application.xml文件
第五步:创建测试类
基于XML文件的DI依赖注入:
DI的语法分类:
setter设值注入:
构造注入:
注入内部 Beans:
注入集合:
自动注入:
自动装配模式:
自动装配的局限性:
ByName:
ByType:
由构造函数自动装配
基于注解的配置:
对象创建及基本属性注入:
扫描多个包:
引用类型注入:
IOC(Inversion of Control):控制反转,是一种理论,概念,思想。把对象的创建,赋值,管理工作交给代码之外的容器实现,也就是对象的创建是由其他的外部资源完成。
什么是控制反转:
- 控制:创建对象,对象的属性赋值,对象之间的关系管理。
- 反转:把原来的开发人员管理,创建对象的权限转移给代码之外的容器实现。由容器代替开发人员管理对象,创建对象。
- 正转:由开发人员在代码中实现,使用new构造方法创建对象,开发人员主动管理对象。
- 容器:一个服务器软件,一个框架(spring)
Spring 容器是 Spring 框架的核心。容器将创建对象,把它们连接在一起,配置它们,并管理他们的整个生命周期从创建到销毁。Spring 容器使用依赖注入(DI)来管理组成一个应用程序的组件,这些对象被称为 Spring Beans。
通过阅读配置元数据提供的指令,容器知道对哪些对象进行实例化,配置和组装。配置元数据可以通过 XML,Java 注释或 Java 代码来表示。 Spring IoC 容器利用 Java 的 POJO 类和配置元数据来生成完全配置和可执行的系统或应用程序。
IOC 容器具有依赖注入功能的容器,它可以创建对象,IOC 容器负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。通常new一个实例,控制权由程序员控制,而"控制反转"是指new实例工作不由程序员来做而是交给Spring容器来做。在Spring中BeanFactory是IOC容器的实际代表者。
Java中创建对象的方式:
- 构造方法
- 反射
- 克隆
- 序列化
- ioc创建对象
- 动态代理
使用IoC的目的:减少对代码的改动,也能实现不同功能。实现解耦合。
Spring 提供了以下两种不同类型的容器:
容器 & 描述 | |
---|---|
1 | Spring BeanFactory 容器 它是最简单的容器,给 DI 提供了基本的支持,它用 org.springframework.beans.factory.BeanFactory 接口来定义。BeanFactory 或者相关的接口,如 BeanFactoryAware,InitializingBean,DisposableBean,在 Spring 中仍然存在具有大量的与 Spring 整合的第三方框架的反向兼容性的目的。 |
2 | Spring ApplicationContext 容器 该容器添加了更多的企业特定的功能,例如从一个属性文件中解析文本信息的能力,发布应用程序事件给感兴趣的事件监听器的能力。该容器是由 org.springframework.context.ApplicationContext 接口定义。 |
ApplicationContext 容器包括 BeanFactory 容器的所有功能,所以通常不建议使用BeanFactory。BeanFactory 仍然可以用于轻量级的应用程序,如移动设备或基于 applet 的应用程序,其中它的数据量和速度是显著。
DI 是ioc的技术实现。
DI(Dependency Injection):依赖注入, 只需要在程序中提供要使用的对象名称就可以, 至于对象如何在容器中创建,赋值,查找都由容器内部实现。
spring是使用的di实现了ioc的功能, spring底层创建对象,使用的是反射机制。
spring是一个容器,管理对象,给属性赋值, 底层是反射创建对象。
spring-conetxt 和 spring-webmvc 是spring中的两个模块
spring-context:是ioc功能的,创建对象的。
spring-webmvc做web开发使用的, 是servlet的升级。
spring-webmvc中也会用到spring-context中创建对象的功能的。
导入Spring和junit依赖到pom.xml中:
<!--junit单元测试依赖--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <!--Spring依赖--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.3.9</version> </dependency>
创建一个接口类,在通常业务中,我们通常使用接口来声明方法,通过接口实现类来完成方法,业务逻辑的具体实现!
package org.example; public interface SomeService { void doSome(); }
实现接口中声明的方法:
package org.example.imp; import org.example.SomeService; public class SomeServiceImpl implements SomeService { //空参构造器:spring默认调用: public SomeServiceImpl() { System.out.println("spring调用了SomeServiceImpl的空参构造器!"); } @Override public void doSome() { System.out.println("执行了SomeServiceImp的doSome方法!"); } }
把创建好的实现类交给Spring容器进行管理:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 约束文件路径——xml文件--> <!-- 告诉spring创建对象 声明bean,就是告诉spring要创建某个类的对象 id:对象的自定义名称,唯一值。spring通过这个名称找到对象 class:类的全限定名称(不能是接口,因为spring是反射机制创建对象,必须使用类) --> <bean id="someService" class="org.example.imp.SomeServiceImpl" /> <bean id="someService1" class="org.example.imp.SomeServiceImpl" /> <!-- spring底层完成:SomeService someService = new SomeServiceImp(); spring把创建好的对象放入map中,spring框架有一个map存放对象 springMap.put(id值,对象); 一个bean标签声明一个Java对象。 --> <!-- spring能创建一个非自定义类的对象,创建一个存在的某个类的对象。 --> <bean id="mydate" class="java.util.Date"/> </beans> <!-- spring的配置文件 1.beans:根标签,spring把Java对象称为bean 2.spring-beans.xsd 是约束文件,和mybatis指定 dtd 类似 -->
package org.example; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.util.Date; public class MyTest { /* spring默认创建对象的时间:在创建spring的容器时,会创建配置文件中所有的对象。 spring创建对象:默认调用的是无参构造方法 */ @Test public void test01(){ //使用spring容器创建对象: //1.指定spring配置文件名称 String config = "application.xml"; //2.创建表示spring容器的对象,ApplicationContext //ApplicationContext就是表示spring容器,通过容器对象获取对象 ApplicationContext ac = new ClassPathXmlApplicationContext(config); //从容其中获取某个对象,调用对象方法 //getBean("配置文件中bean的id值") SomeService service = (SomeService) ac.getBean("someService"); //使用spring创建好的对象,调用方法: service.doSome(); } /** * 获取spring容器中Java对象信息 */ @Test public void test02(){ String config = "application.xml"; ApplicationContext ac = new ClassPathXmlApplicationContext(config); //使用spring提供的方法,获取容器中定义的对象数量 int num = ac.getBeanDefinitionCount(); System.out.println("容器中所含对象数量:" + num); //容器中每个定义对象的名称 String[] names = ac.getBeanDefinitionNames(); //增强for循环: for (String name : names){ System.out.println(name); } } /** * 获取一个非自定义类的对象 */ @Test public void test03(){ String config = "application.xml"; ApplicationContext ac = new ClassPathXmlApplicationContext(config); //使用getBean();获取对象 Date md = (Date) ac.getBean("mydate"); System.out.println("系统时间:" + md); } }
Spring框架的核心功能之一就是通过依赖注入的方式来管理Bean之间的依赖关系。在spring的XML配置文件中,给java对象的属性赋值。DI注入:创建对象,给属性赋值。
依赖注入类型 & 描述 | |
---|---|
1 | Constructor-based dependency injection(构造器方法注入) 当容器调用带有多个参数的构造函数类时,实现基于构造函数的 DI,每个代表在其他类中的一个依赖关系。 |
2 | Setter-based dependency injection(setter方法注入) 基于 setter 方法的 DI 是通过在调用无参数的构造函数或无参数的静态工厂方法实例化 bean 之后容器调用 beans 的 setter 方法来实现的。 |
当容器调用一个无参的构造函数或一个无参的静态 factory 方法来初始化你的 bean 后,通过容器在你的 bean 上调用设值函数,基于设值函数的 DI 就完成了。
第一步:创建一个实体类
package org.example.ba01; public class Student { String name; int age; public Student() { } public Student(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } public void setName(String name) { this.name = name; } public void setAge(int age) { this.age = age; } }
第二步:第二步:在resource目录下编写application.xml文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--声明student对象--> <!-- 注入:赋值 di:给属性赋值 简单类型:spring规定在Java的基本数据类型和String都是简单类型。 1.set注入(设置注入):spring调用类的set方法,你可以在set方法中完成属性赋值 1)简单类型注入 <bean id="XXX" class="YYY"> <property name="属性名字" value="此属性的值" /> 一个property只能给一个属性赋值 <property ... > </bean> 2) 引用类型的注入:spring调用类的set方法 <bean id="XXX" class="YYY"> <property name="属性名称" ref="bean的id(对象名称)"/> </bean> --> <bean id="mystudent" class="org.example.ba01.Student"> <property name="name" value="TOM"/> <property name="age" value="19"/> </bean> </beans>
第三步:编写测试类
package org.example; import org.example.ba01.Student; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MyTest { @Test public void test01(){ //定义配置文件路径: String config = "application.xml"; ApplicationContext ac = new ClassPathXmlApplicationContext(config); //从容器中获得student Student myStudent = (Student) ac.getBean("mystudent"); System.out.println("studnet对象:" + myStudent); } }
当容器调用带有一组参数的类构造函数时,基于构造函数的 DI 就完成了,其中每个参数代表一个对其他类的依赖。
第一步:创建实体类
package org.example.ba01; public class School { String name; int number; public School(String name, int number) { this.name = name; this.number = number; } public School(){ } @Override public String toString() { return "School{" + "name='" + name + '\'' + ", number=" + number + '}'; } }
package org.example.ba01; public class Student { String name; int age; //声明一个引用类型 School school; public Student(){ } //创建有参构造方法: public Student(String name, int age,School school) { System.out.println("Student有参构造方法,给属性赋值!"); this.name = name; this.age = age; this.school = school; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + ", school=" + school + '}'; } }
第二步:在resource目录下编写application.xml文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 2.构造注入:spring调用类的有参构造方法,在创建对象的同时,在构造方法中给属性赋值。 构造注入使用 <constructor-arg>标签 <constructor-arg>标签:一个<constructor-arg>表示构造方法一个参数。 <constructor-arg>标签属性: name:表示构造方法名 index:表示构造方法的参数位置,参数从左往右位置是 0,1,2...的顺序 value:构造方法的形参类型是简单类型使用,value ref:构造方法的形参类型是引用类型的,使用ref --> <!-- 声明School对象--> <bean id="mySchool" class="org.example.ba01.School"> <constructor-arg name="name" value="大学"/> <constructor-arg name="number" value="100"/> </bean> <!-- 声明Student对象--> <bean id="myStudent" class="org.example.ba01.Student"> <!-- <constructor-arg name="name" value="Tom"/>--> <!-- <constructor-arg name="age" value="19"/>--> <!-- <constructor-arg name="school" ref="mySchool"/>--> <!-- 使用:index属性,进行赋值:--> <constructor-arg index="0" value="Hurry"/> <constructor-arg index="1" value="19"/> <constructor-arg index="2" ref="mySchool"/> <!-- index属性可以省略,省略后注意赋值顺序和构造函数的排序一致!--> </bean> </beans>
第三步:编写测试类
package org.example; import org.example.ba01.Student; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MyTest { @Test public void test(){ //1.创建配置文件路径: String config = "application.xml"; //2.创建容器: ApplicationContext ac = new ClassPathXmlApplicationContext(config); //3.从容器中获取对象: Student myStudent = (Student) ac.getBean("myStudent"); //4.通过对象调用方法: System.out.println("Student : " + myStudent); } }
Java 内部类是在其他类的范围内被定义的,同理,inner beans 是在其他 bean 的范围内定义的 bean。因此<property />或<constructor-arg />元素中的<bean />元素称为内部bean。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <bean id="outerBean" class="..."> <property name="target"> <bean id="innerBean" class="..."/> </property> </bean> </beans>
内部 Bean 的定义不需要指定 id 和 name 。如果指定了,容器也不会将其作为区分 Bean 的标识符,反而会无视内部 Bean 的 scope 属性。所以内部 Bean 总是匿名的,而且总是随着外部 Bean 创建。
第一步:创建实体类
public class Person { private Man man; public Man getMan() { return man; } public void setMan(Man man) { System.out.println("在setMan方法内"); this.man = man; } public void man() { man.show(); } }
public class Man { private String name; private int age; public Man() { System.out.println("在man的构造函数内"); } public Man(String name, int age) { System.out.println("在man的有参构造函数内"); this.name = name; this.age = age; } public void show() { System.out.println("名称:" + name + "\n年龄:" + age); } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
第二步:在resource目录下编写application.xml文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <bean id="person" class="net.biancheng.Person"> <property name="man"> <bean class="net.biancheng.Man"> <property name="name" value="bianchengbang" /> <property name="age" value="12" /> </bean> </property> </bean> </beans>
第三步:编写测试类
import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MainApp { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml"); Person person = (Person) context.getBean("person"); person.man(); } }
传递多个值,如 Java Collection 类型 List、Set、Map 和 Properties,应该怎么做呢。为了处理这种情况,Spring 提供了四种类型的集合的配置元素,如下所示:
标签 | 说明 |
---|---|
<list> | 用于注入 list 类型的值,允许重复 |
<set> | 用于注入 set 类型的值,不允许重复 |
<map> | 用于注入 key-value 的集合,其中 key-value 可以是任意类型 |
<props> | 用于注入 key-value 的集合,其中 key-value 都是字符串类型 |
可以使用<list>
或<set>
来连接任何 java.util.Collection
的实现或数组。
第一步:创建实体类
import java.util.*; public class JavaCollection { List addressList; Set addressSet; Map addressMap; Properties addressProp; // a setter method to set List public void setAddressList(List addressList) { this.addressList = addressList; } // prints and returns all the elements of the list. public List getAddressList() { System.out.println("List Elements :" + addressList); return addressList; } // a setter method to set Set public void setAddressSet(Set addressSet) { this.addressSet = addressSet; } // prints and returns all the elements of the Set. public Set getAddressSet() { System.out.println("Set Elements :" + addressSet); return addressSet; } // a setter method to set Map public void setAddressMap(Map addressMap) { this.addressMap = addressMap; } // prints and returns all the elements of the Map. public Map getAddressMap() { System.out.println("Map Elements :" + addressMap); return addressMap; } // a setter method to set Property public void setAddressProp(Properties addressProp) { this.addressProp = addressProp; } // prints and returns all the elements of the Property. public Properties getAddressProp() { System.out.println("Property Elements :" + addressProp); return addressProp; } }
第二步:在resource目录下编写application.xml文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <!-- Definition for javaCollection --> <bean id="javaCollection" class="com.tutorialspoint.JavaCollection"> <!-- results in a setAddressList(java.util.List) call --> <property name="addressList"> <list> <value>INDIA</value> <value>Pakistan</value> <value>USA</value> <value>USA</value> </list> </property> <!-- results in a setAddressSet(java.util.Set) call --> <property name="addressSet"> <set> <value>INDIA</value> <value>Pakistan</value> <value>USA</value> <value>USA</value> </set> </property> <!-- results in a setAddressMap(java.util.Map) call --> <property name="addressMap"> <map> <entry key="1" value="INDIA"/> <entry key="2" value="Pakistan"/> <entry key="3" value="USA"/> <entry key="4" value="USA"/> </map> </property> <!-- results in a setAddressProp(java.util.Properties) call --> <property name="addressProp"> <props> <prop key="one">INDIA</prop> <prop key="two">Pakistan</prop> <prop key="three">USA</prop> <prop key="four">USA</prop> </props> </property> </bean> </beans>
第三步:创建测试类
import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MainApp { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("application.xml"); JavaCollection jc=(JavaCollection)context.getBean("javaCollection"); jc.getAddressList(); jc.getAddressSet(); jc.getAddressMap(); jc.getAddressProp(); } }
注入Bean引用:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <!-- Bean Definition to handle references and values --> <bean id="..." class="..."> <!-- Passing bean reference for java.util.List --> <property name="addressList"> <list> <ref bean="address1"/> <ref bean="address2"/> <value>Pakistan</value> </list> </property> <!-- Passing bean reference for java.util.Set --> <property name="addressSet"> <set> <ref bean="address1"/> <ref bean="address2"/> <value>Pakistan</value> </set> </property> <!-- Passing bean reference for java.util.Map --> <property name="addressMap"> <map> <entry key="one" value="INDIA"/> <entry key ="two" value-ref="address1"/> <entry key ="three" value-ref="address2"/> </map> </property> </bean> </beans>
注入 null 和空字符串的值:
<bean id="..." class="exampleBean"> <property name="email" value=""/> </bean>
<bean id="..." class="exampleBean"> <property name="email"><null/></property> </bean>
自动装配就是指 Spring 容器在不使用 <constructor-arg> 和<property> 标签的情况下,可以自动装配(autowire)相互协作的 Bean 之间的关联关系,将一个 Bean 注入其他 Bean 的 Property 中。
下列自动装配模式,它们可用于指示 Spring 容器为来使用自动装配进行依赖注入。你可以使用<bean>
元素的 autowire 属性为一个 bean 定义指定自动装配模式。
名称 | 说明 |
---|---|
no | 默认值,表示不使用自动装配,Bean 依赖必须通过 ref 元素定义。 |
byName | 根据 Property 的 name 自动装配,如果一个 Bean 的 name 和另一个 Bean 中的 Property 的 name 相同,则自动装配这个 Bean 到 Property 中。 |
byType | 根据 Property 的数据类型(Type)自动装配,如果一个 Bean 的数据类型兼容另一个 Bean 中 Property 的数据类型,则自动装配。 |
constructor | 类似于 byType,根据构造方法参数的数据类型,进行 byType 模式的自动装配。 |
autodetect(3.0版本不支持) | 如果 Bean 中有默认的构造方法,则用 constructor 模式,否则用 byType 模式。 |
可以使用 byType 或者 constructor 自动装配模式来连接数组和其他类型的集合。
当自动装配始终在同一个项目中使用时,它的效果最好。如果通常不使用自动装配,它可能会使开发人员混淆的使用它来连接只有一个或两个 bean 定义。不过,自动装配可以显著减少需要指定的属性或构造器参数,但你应该在使用它们之前考虑到自动装配的局限性和缺点。
限制 | 描述 |
---|---|
重写的可能性 | 你可以使用总是重写自动装配的 <constructor-arg>和 <property> 设置来指定依赖关系。 |
原始数据类型 | 你不能自动装配所谓的简单类型包括基本类型,字符串和类。 |
混乱的本质 | 自动装配不如显式装配精确,所以如果可能的话尽可能使用显式装配。 |
第一步:创建实体类
package org.example.ba02; public class School { String name; int number; public School(String name, int number) { this.name = name; this.number = number; } public School(){ } @Override public String toString() { return "School{" + "name='" + name + '\'' + ", number=" + number + '}'; } }
package org.example.ba02; public class Student { String name; int age; //声明一个引用类型 School school = null;//要和配置文件中School类的<bean>的id值相同 @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + ", school=" + school + '}'; } public void setName(String name) { this.name = name; } public void setAge(int age) { this.age = age; } public void setSchool(School school) { this.school = school; } }
第二步:在resource目录下编写application.xml文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 引用类型的自动注入:spring框架根据某些规则可以给引用类型给类型赋值,不用你在给引用类型赋值 使用的规则常用的是byName,byType. 1.byName(按名称注入):java类中引用类型的属性名和spring容器中(配置文件)<bean>id名称一样,且数据类型一致 这样的容器中的bean,spring就能够赋值给引用类型。 语法: <bean id="XXX" class="YYY" autowire="byName"> 简单类型属性赋值 </bean> 2.byType(按类型注入):java类中引用数据类型和spring容器中(配置文件)<bean>的class属性是同源关系, 这样的bean能够赋值给引用类型。 同源:同一类 1.Java类中引用类型的数据类型和bean的class的值是一样的。 2.Java类中引用类型的数据类型和bean的class的值是父子类关系的。 3.Java类中引用类型的数据类型和bean的class的值接口和实现类关系的。 语法: <bean id="XXX" class="YYY" autowire="byType"> 简单类型属性赋值 </bean> --> <!-- 声明School对象--> <bean id="school" class="org.example.ba02.School"> <!--id值要和Student类的School属性名一致--> <constructor-arg name="name" value="大学"/> <constructor-arg name="number" value="100"/> </bean> <!-- 声明Student对象 byName自动注入--> <bean id="myStudent" class="org.example.ba02.Student" autowire="byName"> <property name="name" value="AJX"/> <property name="age" value="19"/> </bean> <!-- 声明Student对象 byType自动注入--> <bean id="myStudent01" class="org.example.ba02.Student" autowire="byType"> <property name="name" value="Kay" /> <property name="age" value="20"/> </bean> </beans>
第三步:创建测试类
package org.example; import org.example.ba02.Student; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MyTest01 { @Test public void test01(){ //1.创建配置文件路径: String config = "application.xml"; //2.创建容器对象: ApplicationContext ac = new ClassPathXmlApplicationContext(config); //3.通过容器获取对象: Student myStudent = (Student) ac.getBean("myStudent"); //4.通过对象调用方法: System.out.println("Student :" + myStudent); } @Test public void test02(){ //1.创建配置文件路径: String config = "application.xml"; //2.创建容器对象: ApplicationContext ac = new ClassPathXmlApplicationContext(config); //3.通过容器获取对象: Student myStudent = (Student) ac.getBean("myStudent01"); //4.通过对象调用方法: System.out.println("Student :" + myStudent); } }
这种模式由属性类型指定自动装配。Spring
容器看作 beans
,在 XML
配置文件中 beans
的 autowire
属性设置为 byType
。然后,如果它的 type
恰好与配置文件中 beans
名称中的一个相匹配,它将尝试匹配和连接它的属性。如果找到匹配项,它将注入这些 beans
,否则,它将抛出异常。
第一步:创建实体类
public class TextEditor { private SpellChecker spellChecker; private String name; public void setSpellChecker( SpellChecker spellChecker ) { this.spellChecker = spellChecker; } public SpellChecker getSpellChecker() { return spellChecker; } public void setName(String name) { this.name = name; } public String getName() { return name; } public void spellCheck() { spellChecker.checkSpelling(); } }
public class SpellChecker { public SpellChecker(){ System.out.println("Inside SpellChecker constructor." ); } public void checkSpelling() { System.out.println("Inside checkSpelling." ); } }
第二步:在resource目录下编写application.xml文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <!-- Definition for textEditor bean --> <bean id="textEditor" class="com.tutorialspoint.TextEditor" autowire="byType"> <property name="name" value="Generic Text Editor" /> </bean> <!-- Definition for spellChecker bean --> <bean id="SpellChecker" class="com.tutorialspoint.SpellChecker"> </bean> </beans>
第三步:创建测试类
import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MainApp { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("application.xml"); TextEditor te = (TextEditor) context.getBean("textEditor"); te.spellCheck(); } }
这种模式与 byType 非常相似,但它应用于构造器参数。Spring 容器看作 beans,在 XML 配置文件中 beans 的 autowire 属性设置为 constructor。然后,它尝试把它的构造函数的参数与配置文件中 beans 名称中的一个进行匹配和连线。如果找到匹配项,它会注入这些 bean,否则,它会抛出异常。
通过spring的注解完成Java对象的创建,属性的赋值。代替xml文件
从 Spring 2.5 开始就可以使用注解来配置依赖注入。而不是采用 XML 来描述一个 bean 连线,你可以使用相关类,方法或字段声明的注解,将 bean 配置移动到组件类本身。
在 XML 注入之前进行注解注入,因此后者的配置将通过两种方式的属性连线被前者重写。
注解连线在默认情况下在 Spring 容器中不打开。因此,在可以使用基于注解的连线之前,我们将需要在我们的 Spring 配置文件中启用它。所以如果你想在 Spring 应用程序中使用的任何注解,可以考虑到下面的配置文件。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <context:annotation-config base-package="包路径"/> <!-- bean definitions go here --> </beans>
1)@Component
可以使用此注解描述 Spring 中的 Bean,但它是一个泛化的概念,仅仅表示一个组件(Bean),并且可以作用在任何层次。使用时只需将该注解标注在相应类上即可。
2)@Repository
用于将数据访问层(DAO层)的类标识为 Spring 中的 Bean,其功能与 @Component 相同。
3)@Service
通常作用在业务层(Service 层),用于将业务层的类标识为 Spring 中的 Bean,其功能与 @Component 相同。
4)@Controller
通常作用在控制层(如 Struts2 的 Action、SpringMVC 的 Controller),用于将控制层的类标识为 Spring 中的 Bean,其功能与 @Component 相同。
5)@Autowired
可以应用到 Bean 的属性变量、属性的 setter 方法、非 setter 方法及构造函数等,配合对应的注解处理器完成 Bean 的自动配置工作。默认按照 Bean 的类型进行装配。
6)@Resource
作用与 Autowired 相同,区别在于 @Autowired 默认按照 Bean 类型装配,而 @Resource 默认按照 Bean 实例名称进行装配。
@Resource 中有两个重要属性:name 和 type。
Spring 将 name 属性解析为 Bean 的实例名称,type 属性解析为 Bean 的实例类型。如果指定 name 属性,则按实例名称进行装配;如果指定 type 属性,则按 Bean 类型进行装配。如果都不指定,则先按 Bean 实例名称装配,如果不能匹配,则再按照 Bean 类型进行装配;如果都无法匹配,则抛出 NoSuchBeanDefinitionException 异常。
7)@Qualifier
与 @Autowired 注解配合使用,会将默认的按 Bean 类型装配修改为按 Bean 的实例名称装配,Bean 的实例名称由 @Qualifier 注解的参数指定。
第一步:创建实体类
package org.example; import org.springframework.stereotype.Component; /** * @Component: 创建对象的,等同于<bean>的功能 * 属性:value 就是对象的名称,也就是bean的id值 * value的值是唯一的,创建的对象在整个spring容器中就一个 * 位置:在类的上面 * * @Component(value = "myStudent")等同于 <bean id="myStudent" class="org.example.Student" /> * * spring中和@component 功能一致,创建对对象的注解还有: * 1、@Repository(用在持久层类的上面):放在dao的实现类的上面,表示创建dao对象,dao对象是能访问数据库的。 * 2、@Service(用在业务层类的上面):放在service的实现类上面,创建service对象,service对象是做业务处理,可以有事务功能的。 * 3、@Controller(用在控制器的上面):放在控制器(处理器)类的上面,创建控制器对象的 * * 以上三个注解使用语法和@Component一致。都能创建对象,但是这三个注释还有额外的功能 * * @Repository,@Service,@Controller是给项目对象分层的。 */ //省略value //@Component("myStudent") //不指定对象名称,由spring默认提供,value值为:类名首字母小写 //@Component //显示的使用value属性 @Component(value = "myStudent") public class Student { String name; int age; public Student(){ } public Student(String name, int age) { this.name = name; this.age = age; } public void setName(String name) { this.name = name; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
第二步:在resource目录下编写application.xml文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!-- 声明组件扫描器(component-scan) 组件:Java对象 base-package:指定注解在你的项目中的包名 component-scan工作方式:spring会扫描遍历base-package指定的包,把包中的所有类, 找到类中的注解,按照注解功能创建对象,给属性赋值 加入component-scan标签,配置文件的变化: http://www.springframework.org/schema/context ——命名空间 https://www.springframework.org/schema/context/spring-context.xsd ——url 1.加入一个新的约束文件spring-context.xsd 2.给这个新的约束文件起个命名空间的名称 --> <context:component-scan base-package="org.example"/> </beans>
第三步:创建测试类
package org.example; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MyTest { @Test public void test01(){ //1.创建配置文件路径: String config = "applicationContext.xml"; //2.创建容器: ApplicationContext ac = new ClassPathXmlApplicationContext(config); //3.通过容器获取对象: Student myStudent = (Student) ac.getBean("myStudent"); //4.通过对象调用方法: System.out.println("Student:" + myStudent); } }
扫描多个包:
<!--指定多个包扫描的三种方式--> <!--第一种方式:使用多次扫描组件,指定不同的包--> <context:component-scan base-package="包路径1"/> <context:component-scan base-package="包路径2"/> <!--第二种方式:使用分隔符(;或者,)分隔多个包--> <context:component-scan base-package="包路径1;包路径2"/> <!--第三种方式:指定父包--> <context:component-sacn base-package="父包"/>
第一步:创建实体类
package org.example; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @Component("mySchool") public class School { @Value("重庆邮电大学") String name; @Value("南山之颠,黄河以北") String address; public School() { } public School(String name, String address) { this.name = name; this.address = address; } public void setName(String name) { this.name = name; } public void setAddress(String address) { this.address = address; } @Override public String toString() { return "School{" + "name='" + name + '\'' + ", address='" + address + '\'' + '}'; } }
package org.example; 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; @Component(value = "myStudent") public class Student { /** * @Value: 简单类型的属性赋值 * 属性:value 是String类型的,表示简单类型的属性值 * 位置:1.在属性定义的上面,无需set方法 (推荐使用) * 2.在set方法的上面 * * * @Valude: 引用类型的属性赋值 * @Autowired: spring框架提供注解,实现引用类型的赋值。 * spring中通过注解给引用类型赋值,使用的是自动注入原理,支持byName,byType * * @Autowired:默认使用byType自动注入 * * 属性: * required ,是一个boolean类型的,默认true * required=true:表示引用类型赋值失败,程序报错,并终止执行。 * required=false:表示引用类型赋值失败,程序正常执行,引用类型是null * * 位置:1.在属性定义的上面,无需set方法(推荐使用) * 2.在set方法上面 * * @Autowired:使用byName注入方式: * 1.在属性上加@Autowired * 2.在属性上加入@Quallifier(value="bean的id") :表示使用指定名称的bean完成对象创建 * * * 引用类型 * @Resource: 来自jdk中的注解,spring框架提供了对这个注解的功能支持,可以使用他给引用类型属性赋值。 * 使用的也是自动类型注入原理,支持byName,byType,默认是byName * * 位置:1.在属性上方定义,无需set方法(推荐使用) * 2.在set方法上 * * @Resource:只是用byName方式,需要增加一个属性 name * name的值是bean的id(名称) */ //默认是byName:先使用byName自定注入,如果byName赋值失效,再使用byType // @Value(value = "Tom") //value可以省 // 使用资源文件赋值: @Value("${name}") String name; // @Value(value = "21") @Value("${age}") int age; //引用类型属性: @Autowired @Qualifier(value = "mySchool") School school; public Student(){ } public Student(String name, int age) { this.name = name; this.age = age; } // @Value(value = "harry") // public void setName(String name) { // this.name = name; // } // // public void setAge(int age) { // this.age = age; // } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + ", school=" + school + '}'; } }
第二步:xml配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!-- 声明组件扫描器(component-scan) 组件:Java对象 base-package:指定注解在你的项目中的包名 component-scan工作方式:spring会扫描遍历base-package指定的包,把包中的所有类, 找到类中的注解,按照注解功能创建对象,给属性赋值 加入component-scan标签,配置文件的变化: http://www.springframework.org/schema/context ——命名空间 https://www.springframework.org/schema/context/spring-context.xsd ——url 1.加入一个新的约束文件spring-context.xsd 2.给这个新的约束文件起个命名空间的名称 --> <context:component-scan base-package="org.example"/> <!-- 声明资源文件路径--> <context:property-placeholder location="MyResource.properties"/> </beans>
properties配置文件
name=Tom age=190
第三步:编写测试类
package org.example; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MyTest { @Test public void test01(){ //1.创建配置文件路径: String config = "applicationContext.xml"; //2.创建容器: ApplicationContext ac = new ClassPathXmlApplicationContext(config); //3.通过容器获取对象: Student myStudent = (Student) ac.getBean("myStudent"); //4.通过对象调用方法: System.out.println("Student:" + myStudent); } }