1 Spring是什么
- Spring是一个开源框架。
- Spring为简化企业级应用开发而生,使用Spring可以使简单的JavaBean实现以前只有EJB才能实现的功能。
- Spring是一个IOC(DI)和AOP容器框架。
- 具体描述Spring:
- 轻量级:Spring是非侵入的。基于Spring开发的应用中的对象可以不依赖于Spring的API。
- 依赖注入(DI,Dependency Injection、IOC)
- 面向切面编程(AOP,Aspect Oriented Programming)
- 容器:Spring是一个容器,因为它包含并且管理应用对象的生命周期。
- 框架:Spring实现了使用简单的组件配置组合成一个复杂的应用。在Spring中可以使用XML和Java注解组合这些对象。
- 一站式:在IOC和AOP的基础上可以整合各种企业应用的开源框架和优秀的第三方类库。
- Spring模块:
2 Spring的HelloWorld
- Spring项目目录结构:
HelloWorld类(JavaBean):
package com.xianhuii.beans; public class HelloWorld { private String name; public void setName(String name) { this.name = name; } public void hello() { System.out.println("hello " + name); } }
Main类(不使用Spring前):
package com.xianhuii.beans; public class Main { public static void main(String[] args) { // 1、实例化 HelloWorld helloWorld = new HelloWorld(); // 2、设值 helloWorld.setName("xianhuii"); helloWorld.hello(); } }
创建SpringConfig配置文件(applicationContext.xml),配置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.xsd"> <!-- 配置Bean --> <bean id="helloworld" class="com.xianhuii.beans.HelloWorld"> <property name="name" value="xianhuii"/> </bean> </beans>
使用Bean:
package com.xianhuii.beans; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Main { public static void main(String[] args) { // 1、创建Spring的IOC容器对象 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); // 2、获取Bean HelloWorld helloworld = (HelloWorld) context.getBean("helloworld"); // 3、使用Bean helloworld.hello(); } }
Spring使用步骤:
- 创建Bean类;
- 配置Bean;
- 使用Bean:
- 创建Spring的IOC容器对象
- 从容器中获取Bean
- 使用Bean
3 什么是IOC、DI
1、IOC
- IOC(Inversion of Control),控制反转:其思想是反转资源获取的方向。
- 传统的资源查找方式要求组件向容器发起请求查找资源。作为回应,容器适时的返回资源。
- 而应用了IOC之后,则是容器主动地将资源推送给它所管理的组件,组件所要做的仅是选择一种合适的方式来接受资源。
- 这种行为也被称为查找的被动形式。
- 个人理解:将对象的创建、赋值等操作交由容器来做。
2、DI
- DI(Dependency Injection),依赖注入:是IOC的另一种表述方式。
- 即组件以一些预先定义要的方式(如setter方法)接受来自容器的资源注入。
- 个人理解:对象的赋值等操作由容器来做。
4 Spring IOC容器
- 在Spring IOC容器读取Bean配置创建Bean实例之前,必须对它进行实例化。只有在容器实例化后,才可以从IOC容器中获取Bean实例并使用。
- Spring提供了两种类型的IOC容器实现:
- BeanFactory:面向框架本身,IOC容器的基本实现。
- ApplicationContext:面向开发者,提供了更多高级的特性,是BeanFactory的子接口。
- 无论使用何种方式,配置文件时都是相同的。
4.1 ApplicationContext
1、主要实现类
- ApplicationContext的两个主要实现类:
- ClassPathXmlApplicationContext:从类路径下加载配置文件。
- FileSystemXmlApplicationContext:从文件系统中加载配置文件。
- ApplicationContext在初始化上下文时就实例化所有单例的Bean(scope="singleton")。
2、获取Bean的方法
通过id;
通过类型;
……
package com.xianhuii.beans; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Main { public static void main(String[] args) { // 1、创建Spring的IOC容器对象 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); // 2、获取Bean // 方式一:根据id获取Bean HelloWorld bean1 = (HelloWorld) context.getBean("helloworld"); // 方式二:根据class类型获取Bean,要求IOC容器中只能有一个该类型的Bean HelloWorld bean2 = context.getBean(HelloWorld.class); // 3、使用Bean } }
5 依赖注入:set方法注入、构造方法注入
Spring支持3种依赖注入的方式:
- 属性注入(setter方法注入)
- 构造器注入
- 工厂方法注入(很少使用,不推荐)
实验类:
public class Car { private String brand; // 品牌 private String crop; // 厂商 private double price; // 价格 public Car() { } public Car(String brand, String crop, double price) { this.brand = brand; this.crop = crop; this.price = price; } public String getBrand() { return brand; } public void setBrand(String brand) { this.brand = brand; } public String getCrop() { return crop; } public void setCrop(String crop) { this.crop = crop; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } @Override public String toString() { return "Car{" + "brand='" + brand + '\'' + ", crop='" + crop + '\'' + ", price=" + price + '}'; } }
1、属性注入
setter方法注入的前提:先调用无参构造器创建对象。
name:setXxx()方法对应的xxx,与成员变量名无关。
value:注入的字面量值。
ref:注入其他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.xsd"> <!-- 配置Car,属性注入(setter方法注入) --> <bean id="car" class="Car"> <property name="brand" value="Audi"></property> <property name="crop" value="Yiqi"></property> <property name="price" value="40000"></property> </bean> </beans>
2、构造器注入
默认通过在构造器形参中的顺序进行赋值。
可以显示指明index、name、type等进行注入,它们可以配合使用。
如果有多个构造器,注意使用的注入方法不能引起歧义,否则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"> <!-- 配置Car,构造器注入 --> <!-- 默认按照构造器形参的顺序进行注入 --> <bean id="car1" class="Car"> <constructor-arg value="BMW"></constructor-arg> <constructor-arg value="huachen"></constructor-arg> <constructor-arg value="500000"></constructor-arg> </bean> <!-- 显示指定构造器形参的索引进行注入,可以自定义顺序 --> <bean id="car2" class="Car"> <constructor-arg index="0" value="BMW"></constructor-arg> <constructor-arg index="2" value="500000"></constructor-arg> <constructor-arg index="1" value="huachen"></constructor-arg> </bean> <!-- 显示指定构造器形参的名字进行注入 --> <bean id="car3" class="Car"> <constructor-arg name="brand" value="BMW"></constructor-arg> <constructor-arg name="price" value="500000"></constructor-arg> <constructor-arg name="crop" value="huachen"></constructor-arg> </bean> <!-- 显示指定构造器形参的类型进行注入 --> <bean id="car4" class="Car"> <constructor-arg type="java.lang.String" value="BMW"></constructor-arg> <constructor-arg type="double" value="500000"></constructor-arg> <constructor-arg type="java.lang.String" value="huachen"></constructor-arg> </bean> </beans>
- 可以将value属性,转换成value子标签的方式进行注入:
<?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"> <bean id="car1" class="Car"> <constructor-arg> <value>Audi</value> </constructor-arg> <constructor-arg> <value>huachen</value> </constructor-arg> <constructor-arg> <value>50000</value> </constructor-arg> </bean> </beans>
6 特殊字符的注入:value子标签
- 实验类:
public class Book { private int isbn; private String bookName; public int getIsbn() { return isbn; } public void setIsbn(int isbn) { this.isbn = isbn; } public String getBookName() { return bookName; } public void setBookName(String bookName) { this.bookName = bookName; } @Override public String toString() { return "Book{" + "isbn=" + isbn + ", bookName='" + bookName + '\'' + '}'; } }
- 特殊字符注入:
<?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"> <bean id="book1" class="Book"> <property name="isbn"> <value>1001</value> </property> <!-- 方式一:使用转义字符 --> <property name="bookName" value="<<Spring>>"></property> </bean> <bean id="book2" class="Book"> <property name="isbn"> <value>1001</value> </property> <!-- 方式二:使用CDATA --> <property name="bookName"> <!-- <![CDATA[想些啥,就写啥]]> --> <value><![CDATA[<<Spring>>]]]></value> </property> </bean> </beans>
7 引用其他的Bean:ref属性
- 实验类(Car如上):
public class Person { private String name; private int age; private Car car; // 人有一辆车 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; } public Car getCar() { return car; } public void setCar(Car car) { this.car = car; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + ", car=" + car + '}'; } }
- 引用其他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.xsd"> <bean id="person" class="Person"> <property name="name" value="莫小贝"></property> <property name="age" value="12"></property> <property name="car" ref="car"></property> </bean> <bean id="car" class="Car"> <property name="brand" value="Audi"></property> <property name="crop" value="Yiqi"></property> <property name="price" value="40000"></property> </bean> </beans>
8 内部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.xsd"> <bean id="person" class="Person"> <property name="name" value="莫小贝"></property> <property name="age" value="12"></property> <property name="car"> <bean class="Car"> <property name="brand" value="Audi"></property> <property name="crop" value="Yiqi"></property> <property name="price" value="40000"></property> </bean> </property> </bean> </beans>
9 集合注入:List、Set、数组
1、List
实验类:
import java.util.List; public class PersonList { private String name; private int age; private List<Car> cars; 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; } public List<Car> getCars() { return cars; } public void setCars(List<Car> cars) { this.cars = cars; } @Override public String toString() { return "PersonList{" + "name='" + name + '\'' + ", age=" + age + ", cars=" + cars + '}'; } }
注入List:
<?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"> <bean id="person" class="PersonList"> <property name="name" value="莫小贝"></property> <property name="age" value="12"></property> <property name="cars"> <list> <ref bean="car1"/> <ref bean="car2"/> <bean class="Car"> <property name="brand" value="Audi"></property> <property name="crop" value="Yiqi"></property> <property name="price" value="40000"></property> </bean> </list> </property> </bean> <bean id="car1" class="Car"> <property name="brand" value="Audi"></property> <property name="crop" value="Yiqi"></property> <property name="price" value="40000"></property> </bean> <bean id="car2" class="Car"> <property name="brand" value="Audi"></property> <property name="crop" value="Yiqi"></property> <property name="price" value="40000"></property> </bean> </beans>
Set、数组只需将标签改为set、array即可。
10 Map注入
实验类:
import java.util.Map; public class PersonMap { private String name; private int age; private Map<String, Car> cars; @Override public String toString() { return "PersonMap{" + "name='" + name + '\'' + ", age=" + age + ", cars=" + cars + '}'; } 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; } public Map<String, Car> getCars() { return cars; } public void setCars(Map<String, Car> cars) { this.cars = cars; } }
Map注入:
<?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"> <bean id="personMap" class="PersonMap"> <property name="name" value="莫小贝"></property> <property name="age" value="12"></property> <property name="cars"> <map> <!--<entry key="" key-ref="" value="" value-ref="" value-type=""></entry>--> <entry key="Audi" value-ref="car"></entry> </map> </property> </bean> <bean id="car" class="Car"> <property name="brand" value="Audi"></property> <property name="crop" value="Yiqi"></property> <property name="price" value="40000"></property> </bean> </beans>
11 p命名空间
为了简化XML文件的配置,越来越多的XML文件采用属性而非子元素配置信息。
Spring从2.5版本开始引入了一个新的p命名空间,可以通过<bean>元素属性的方式配置Bean的属性。</bean>
使用p命名空间后,基于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:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- p命名空间 --> <bean id="car" class="Car" p:brand="Audi" p:crop="Yiqi" p:price="40000"></bean> <bean id="person" class="Person" p:age="30" p:name="张三" p:car-ref="car"></bean> </beans>
12 自动装配
Spring IOC容器可以自动装配Bean,需要做的仅仅是在<bean>的autowire属性里指定自动装配的模式。</bean>
基本值不可以自动装配,必须手动配置。
引用值才可以设置成自动装配。
方式:
- byType(根据类型自动装配):通过已设置好的bean的类型,与此Bean的属性的类型进行匹配。若IOC容器中有多个与目标Bean类型一致的Bean,Spring将无法判定哪个Bean最适合该属性,所以不能执行自动装配。
- byName(根据名称自动装配):将已设置好的Bean的id,与本类中的setter方法进行匹配。
- constructor(通过构造器自动装配):当Bean中存在多个构造器时,此种自动装配方式将会很复杂。不推荐使用。
实验类1:
public class Address { private String city; private String street; public String getCity() { return city; } public void setCity(String city) { this.city = city; } public String getStreet() { return street; } public void setStreet(String street) { this.street = street; } @Override public String toString() { return "Address{" + "city='" + city + '\'' + ", street='" + street + '\'' + '}'; } }
实验类2:
public class Car { private String brand; // 品牌 private double price; // 价格 public String getBrand() { return brand; } public void setBrand(String brand) { this.brand = brand; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } @Override public String toString() { return "Car{" + "brand='" + brand + '\'' + ", price=" + price + '}'; } }
实验类3:
public class Person { private String name; private Address address; private Car car; public String getName() { return name; } public void setName(String name) { this.name = name; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } public Car getCar() { return car; } public void setCar(Car car) { this.car = car; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", address=" + address + ", car=" + car + '}'; } }
配置:
<?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:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="address" class="Address"> <property name="city" value="beijing"></property> <property name="street" value="huilongguan"></property> </bean> <bean id="car" class="Car" p:brand="Audi" p:price="400000"></bean> <!-- autowire="byName":通过已设置好的bean的id值,与此Bean的setter方法名进行匹配 --> <bean id="person1" class="Person" p:name="Tom" autowire="byName"></bean> <!-- autowire="byType":通过已设置好的bean的类型,与此Bean的属性的类型进行匹配 --> <bean id="person2" class="Person" p:name="Tom" autowire="byType"></bean> </beans>
13 Bean之间的关系:继承、依赖
1、继承
parent:指定父Bean,实现继承关系。
abstract="true":指定为抽象Bean,抽象的Bean不能实例化。
abstract不是必须的。
<?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:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="address" class="Address" abstract="true"> <property name="city" value="Beijing"></property> <property name="street" value="HuiLongGuan"></property> </bean> <bean id="address1" parent="address"> <property name="street" value="WuDaoKou"></property> </bean> </beans>
2、依赖
depends-on="car":表明此Bean创建之前,必须先创建car这个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" 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"> <!-- 继承 --> <bean id="address" class="Address" abstract="true"> <property name="city" value="Beijing"></property> <property name="street" value="HuiLongGuan"></property> </bean> <bean id="address1" parent="address"> <property name="street" value="WuDaoKou"></property> </bean> <!-- 依赖 --> <bean id="person" class="Person" depends-on="car"> <property name="name" value="Jerry"></property> <property name="address" ref="address1"></property> <property name="car" ref="car"></property> </bean> <bean id="car" class="Car"> <property name="brand" value="BMW"></property> <property name="price" value="400000"></property> </bean> </beans>
14 Bean的作用域
在Spring中,可以在<bean>元素的scope属性里设置Bean的作用域。</bean>
默认情况下,Spring只为每个在IOC容器里声明的Bean创建唯一一个实例,整个实例IOC容器范围内都能共享该Bean。所有后续的getBean()调用和Bean引用都将返回这个唯一的Bean实例。该作用域被称为singleton,它是所有Bean的默认作用域。
scope:
- singleton:单例(默认值)。在IOC容器中,只有一个该bean的实例对象。并且该bean的对象会在IOC容器初始化的时候创建。
- prototype:原型。在IOC容器中,有多个该bean的实例对象。不会在IOC容器初始化的时候创建,而是在每次getBean()的时候才会创建一个新的对象返回。
- request:一次请求期间。每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境。
- session:一次会话期间。同一个HTTP Session共享一个Bean,不同的HTTP Session使用不同的Bean。该作用于仅适用于WebApplicationContext环境。
配置:
<?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"> <!-- scope:配置bean的作用域 singleton:1、单例,整个IOC容器中只有一个bean的实例; 2、该bean的实例会在IOC容器实例化的时候创建。 prototype:1、原型,每次请求getBean()都会新创建一个bean的实例; 2、在IOC容器实例化的时候不会创建,在请求getBean()时才会创建。 request:一次请求之间。 session:一次会话之间。 --> <bean id="address1" class="Address" scope="singleton"> <property name="city" value="Beijing"></property> <property name="street" value="SiDaokou"></property> </bean> <bean id="address2" class="Address" scope="prototype"> <property name="city" value="Beijing"></property> <property name="street" value="SiDaokou"></property> </bean> </beans>
测试:
import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); Object singleton1 = context.getBean("address1"); Object singleton2 = context.getBean("address1"); System.out.println(singleton1 == singleton2); // true Object prototype1 = context.getBean("address2"); Object prototype2 = context.getBean("address2"); System.out.println(prototype1 == prototype2); // false } }
15 使用外部属性文件
在src下创建db.properties文件:
jdbc.driver=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC jdbc.username=root jdbc.password=root
在applicationContext.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"> <!-- 引入外部化的配置文件 --> <context:property-placeholder location="classpath:db.properties"/> <!-- 配置c3p0连接池(数据源) --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driver}"></property> <property name="jdbcUrl" value="${jdbc.url}"></property> <property name="user" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> </bean> </beans>
使用:
import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLException; public class SpringTest { public static void main(String[] args) throws SQLException { // 1、实例化容器 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); // 2、获取数据源 DataSource dataSource = (DataSource) context.getBean("dataSource"); // 3、获取连接 Connection connection = dataSource.getConnection(); // 4、使用 } }
16 Bean的生命周期
生命周期(不考虑后置处理器):
- 调用构造器创建对象;
- 给对象的属性赋值;
- 调用初始化方法。初始化方法是通过init-method来指定的;
- 使用对象;
- 调用销毁方法。销毁方法是通过destroy-method来指定的。
实验类:
public class Car { private String brand; // 品牌 private double price; // 价格 public Car() { System.out.println("1、创建对象"); } public void init() { System.out.println("3、init"); } public void destroy() { System.out.println("5、destroy"); } public String getBrand() { return brand; } public void setBrand(String brand) { this.brand = brand; System.out.println("2、setBrand"); } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; System.out.println("2、setPrice"); } @Override public String toString() { return "Car{" + "brand='" + brand + '\'' + ", price=" + price + '}'; } }
配置:
<?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"> <bean id="car" class="Car" init-method="init" destroy-method="destroy"> <property name="brand" value="Ford"></property> <property name="price" value="250000"></property> </bean> </beans>
测试:
import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringTest { public static void main(String[] args) { // 1、实例化容器 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); // 2、获取bean Car car = (Car) context.getBean("car"); // 3、使用bean System.out.println("4、使用car:" + car); // 4、关闭容器 ((ClassPathXmlApplicationContext) context).close(); } }
结果:
17 静态工厂配置Bean
实验类:
import java.util.HashMap; import java.util.Map; public class StaticObjectFactory { private static Map<String, Car> cars = new HashMap<>(); static { cars.put("audi", new Car("Audi", 400000)); cars.put("bmw", new Car("bmw", 500000)); } /** * 静态工厂方法 * @return */ public static Car getCar(String carName) { return cars.get(carName); } }
配置:
<?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"> <!-- 静态工厂配置bean class:静态工厂类 factory-method:静态工厂方法 --> <bean id="car" class="StaticObjectFactory" factory-method="getCar"> <constructor-arg value="audi"></constructor-arg> </bean> </beans>
测试:
import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringTest { public static void main(String[] args) { // 1、实例化容器 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); // 2、获取bean Car car = (Car) context.getBean("car"); // 3、使用bean System.out.println(car); //Car{brand='Audi', price=400000.0} } }
18 实例工厂方法
实验类:
import java.util.HashMap; import java.util.Map; /** * 获取Car对象的工厂: * InstanceObjectFactory iof = new InstanceObjectFactory() * Car car = iof.getCar("bmw") */ public class InstanceObjectFactory { private Map<String, Car> cars = new HashMap<>(); public InstanceObjectFactory() { cars.put("audi", new Car("Audi", 400000)); cars.put("bmw", new Car("bmw", 500000)); } /** * 实例工厂方法 * @return */ public Car getCar(String carName) { return cars.get(carName); } }
配置:
<?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"> <!-- 实例工厂配置bean factory-bean:指定工厂bean factory-method:指定工厂方法 --> <bean id="iof" class="InstanceObjectFactory"></bean> <bean id="car" factory-bean="iof" factory-method="getCar"> <constructor-arg value="bmw"></constructor-arg> </bean> </beans>
测试:
import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringTest { public static void main(String[] args) { // 1、实例化容器 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); // 2、获取bean Car car = (Car) context.getBean("car"); // 3、使用bean System.out.println(car); //Car{brand='bmw', price=500000.0} } }
19 FactoryBean方式配置Bean
- FactoryBean:
实验类:
import org.springframework.beans.factory.FactoryBean; public class MyFactoryBean implements FactoryBean<Car> { /** * 返回最终的对象。 * @return * @throws Exception */ @Override public Car getObject() throws Exception { return new Car("QQ", 30000); } /** * 返回对象的类型。 * @return */ @Override public Class<?> getObjectType() { return Car.class; } /** * 对象是否为单例。 * @return */ @Override public boolean isSingleton() { return true; } }
配置:
<?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"> <!-- FactoryBean的方式配置Bean:通过MyFactoryBean的getObject获取。--> <bean id="car" class="MyFactoryBean"></bean> </beans>
测试:
import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringTest { public static void main(String[] args) { // 1、实例化容器 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); // 2、获取bean Car car = (Car) context.getBean("car"); // 3、使用bean System.out.println(car); //Car{brand='QQ', price=30000.0} } }
20 注解方式配置Bean
- 组件扫描(component scanning):Spring能够从classpath下自动扫描,侦测和实例化具有特定注解的组件。
- 特定组件包括:
- @Comonent:基本注解,标识一个受Spring管理的组件。
- @Respository:标识持久层组件。
- @Service:标识服务层(业务层)组件。
- @Controller:标识表现层组件。
- 对于扫描到的组件,Spring有默认的命名策略:使用非限定类名,第一个字母小写。也可以在注解中通过value属性值标识组件的名称。
- context:component-scan:开启注解扫描。
- 测试目录:
Controller层:
package com.xianhuii.controller; import org.springframework.stereotype.Controller; /** * 表现层组件 * @Controller的作用:等价于在xml配置文件中: * <bean id="userController" class="com.xianhuii.controller.UserController"></bean> * @Controller注解默认的id值是类名首字母小写,如果想要自己制定,可以使用value属性来指定: * @Controller(value = "id") 或 @Controller("id") */ @Controller public class UserController { }
Service层:
package com.xianhuii.service; import org.springframework.stereotype.Service; /** * 业务层组件 */ @Service public class UserService { }
DAO层接口:
package com.xianhuii.dao; public interface UserDao { }
DAO层实现类:
package com.xianhuii.dao; import org.springframework.stereotype.Repository; @Repository public class UserDaoJdbcImpl implements UserDao { }
配置:
<?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"> <!-- 开启注解扫描 --> <context:component-scan base-package="com.xianhuii"></context:component-scan> </beans>
测试:
package com.xianhuii.test; import com.xianhuii.controller.UserController; import com.xianhuii.dao.UserDaoJdbcImpl; import com.xianhuii.service.UserService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringTest { public static void main(String[] args) { // 1、实例化容器 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); // 2、获取bean UserController userController = (UserController) context.getBean("userController"); UserService userService = (UserService) context.getBean("userService"); UserDaoJdbcImpl userDaoJdbc = (UserDaoJdbcImpl) context.getBean("userDaoJdbcImpl"); // 3、使用bean System.out.println(userController); System.out.println(userService); System.out.println(userDaoJdbc); } }```
测试结果:
21 context:component-scan
<?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"> <!-- 开启注解扫描 --> <context:component-scan base-package="com.xianhuii"></context:component-scan> <!-- 1、include-filter 需要配合use-default-filters="false" 来使用 --> <!--<context:component-scan base-package="com.xianhuii" use-default-filters="false">--> <!--<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"></context:include-filter>--> <!--</context:component-scan>--> <!-- 2、exclude-filter 不需要配合use-default-filters="false" 来使用 --> <!--<context:component-scan base-package="com.xianhuii">--> <!--<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"></context:exclude-filter>--> <!--</context:component-scan>--> <!-- 3、assignable 通过指定类名的方式来指定扫描的类与不扫描的类 --> <!--<context:component-scan base-package="com.xianhuii" use-default-filters="false">--> <!--<context:include-filter type="assignable" expression="com.xianhuii.service.UserService"></context:include-filter>--> <!--</context:component-scan>--> </beans>
22 基于注解的方式装配bean
@Autowired:自动装配bean。
DAO层接口:
package com.xianhuii.dao; public interface UserDao { void getUserByUserNameAndPassword(); }
DAO层实现类:
package com.xianhuii.dao; import org.springframework.stereotype.Repository; @Repository public class UserDaoJdbcImpl implements UserDao { @Override public void getUserByUserNameAndPassword() { System.out.println("UserDaoJdbcImpl.getUserByUserNameAndPassword()"); } }
业务层:
package com.xianhuii.service; import com.xianhuii.dao.UserDao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * 业务层组件 */ @Service public class UserService { @Autowired private UserDao userDao; public void handleLogin() { System.out.println("UserService.handleLogin()"); // 处理登录的逻辑 userDao.getUserByUserNameAndPassword(); } }
控制层:
package com.xianhuii.controller; import com.xianhuii.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; /** * 表现层组件 * * @Controller的作用:等价于在xml配置文件中: <bean id="userController" class="com.xianhuii.controller.UserController"></bean> * @Controller注解默认的id值是类名首字母小写,如果想要自己制定,可以使用value属性来指定: * @Controller(value = "id") 或 @Controller("id") */ @Controller public class UserController { @Autowired private UserService userService; public void login() { System.out.println("UserController.login()"); userService.handleLogin(); } }
测试:
package com.xianhuii.test; import com.xianhuii.controller.UserController; import com.xianhuii.dao.UserDaoJdbcImpl; import com.xianhuii.service.UserService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringTest { public static void main(String[] args) { // 1、实例化容器 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); // 2、获取bean UserController userController = (UserController) context.getBean("userController"); // 3、使用bean userController.login(); } }
测试结果:
23 @Autowired具体解释
@Autowired优先采用类型匹配的方式进行bean的装配。
如果有多个类型兼容的bean匹配了,会使用属性名与bean的id值进行匹配。
@Autowired默认情况下required=true,表明此注解修饰的属性必须被装配。可以改为required=false,有就装配,没有就算了。
如下,新增一个DAO实现类:
package com.xianhuii.dao; import org.springframework.stereotype.Repository; @Repository public class UserDaoMyBatisImpl implements UserDao { @Override public void getUserByUserNameAndPassword() { System.out.println("UserDaoMyBatisImpl.getUserByUserNameAndPassword()"); } }
此时,运行由于类型不匹配,同时属性名也不匹配,会报错。
方式一:修改属性名
package com.xianhuii.service; import com.xianhuii.dao.UserDao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * 业务层组件 */ @Service public class UserService { @Autowired private UserDao userDaoMyBatisImpl; public void handleLogin() { System.out.println("UserService.handleLogin()"); // 处理登录的逻辑 userDaoMyBatisImpl.getUserByUserNameAndPassword(); } }
此时,Spring会根据属性名找到id为userDaoMyBatisImpl的bean,测试结果如下:
方式二:使用@Qualifier
package com.xianhuii.service; import com.xianhuii.dao.UserDao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; /** * 业务层组件 */ @Service public class UserService { @Autowired @Qualifier("userDaoMyBatisImpl") private UserDao userDao; public void handleLogin() { System.out.println("UserService.handleLogin()"); // 处理登录的逻辑 userDao.getUserByUserNameAndPassword(); } }
此时,Spring会根据@Qualifier注解的value值找到id为userDaoMyBatisImpl的bean,测试结果如下: