Spring Ioc 容器
什么是Ioc
Ioc即Inversion of control,翻译为控制反转。应用不负责依赖对象的创建维护,转而由外部容器负责。将依赖对象的创建维护的控制交由容器即为控制权的转移,也就是所谓的控制反转--Ioc!
什么是DI
DI(Dependency Injection)依赖注入。向某对象动态地注入其依赖的其它对象的引用。
开发人员无需手动new对象并建立依赖关系,Ioc容器会把实例化对象注入。
依赖注入方式
-
构造器注入
-
方法注入
-
接口注入
Spring Ioc容器
Spring中实现Ioc和DI的组件,用来降低耦合度,简化开发。
Bean
Spring中用来表示组件,可以是任何Java类实例。由Ioc容器管理Bean的生命周期(创建和销毁)
-
BeanFactory(Bean 工厂)
BeanFactory 是 Spring 框架最核心的接口,它提供了高级 IoC 的配置机制;BeanFactory 使管理不同类型的 Java 对象成为可能。 BeanFactory 是 Spring 框架的基础设施,属于底层封装组件,专供 Spring 框架内部使用
-
ApplicationContext ( 应用上下文 )
ApplicationContex 是建立在 BeanFactory 基础之上,提供了更多面向应用的功能。一般称BeanFactory为IoC容器,而称ApplicationContext 为应用上下文。ApplicationContext 面向 Spring 框架的开发者,属于上层封装组件,专供开发者使用。通过 ApplicationContext 应用上下文实例调用其 getBean() 方法从 IoC 容器中即可获取 Bean 对象实例
启动Ioc容器
有三种方式
-
ClassPathXmlApplicationContext(相对路径)
从类路径下的 XML 配置文件中加载上下文定义,把应用上下文定义文件当做类资源
ApplicationContext ctx = new ClassPathXmlApplicationContext(“包路径/beans.xml”)
-
FileSystemXmlApplicationContext(绝对路径)
读取文件系统下的 XML 配置文件并加载上下文定义
ApplicationContext ctx = new FileSystemtXmlApplicationContext(“文件路径/beans.xml”)
-
XmlWebApplicationContext(web 配置路径)
读取 Web 应用下的 XML 配置文件并加载上下文定义
初始化和销毁Ioc容器
//初始化(Ioc容器调用) public void init(){ System.out.println("调用初始化方法"); } //销毁(Ioc容器调用) public void destroy(){ System.out.println("调用销毁方法"); }
加载Ioc容器
//加载Ioc容器方式一 ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("ioc.xml");
//加载Ioc容器方式二 // FileSystemXmlApplicationContext ioc2 = // new FileSystemXmlApplicationContext("E:\\Workout\\Spring001\\src\\main\\resources\\ioc.xml");
装配Bean
装配 Bean 指在 Spring IoC 容器中创建 Bean 组件及建立 Bean 组件之间的依赖关系的过程。(实现 IoC(控制反转)和 DI(依赖注入)) Spring 支持三种装配 Bean 的方式:
-
基于 XML 配置装配 Bean
-
基于注解装配 Bean
-
基于 Java 类装配 Bean
注解装配Bean
<!--开启自动装配注解(默认禁用注解)--> <context:annotation-config/> <!--开启自动扫描Bean--> <context:component-scan base-package="bean"/>
获得Bean
getBean() 两种用法:name:bean的id ; class:bean的类型(唯一)
Boy boy2 == ioc.getBean(Boy.class);//要求boy类型唯一
Boy boy2 = (Boy)ioc.getBean("boy2"); System.out.println(boy2.getGirl());
IoC 注解
-
@Component:标识 Java 类为 Spring Bean 组件(通用注解)
-
@Controller:标识三层架构中表现层的 Java 类为 Spring Bean 组件
-
@Service:标识三层架构中业务逻辑层的 Java 类为 Spring Bean 组件
-
@Repository:标识三层架构中业务持久层的 Java 类为 Spring Bean 组件
DI 注解
-
@Autowired:依赖注入
默认采用byType,byType适用类型唯一。否则使用byName,byName失效则抛出异常,依赖注入的id是属性名.
常用的有
基于属性注入
@Service public class Student { @Autowired private Teacher teacher; }
基于setter方法注入
@Autowired public void setTeacher(Teacher teacher) { this.teacher = teacher; }
基于构造器注入
@Autowired public Student( Teacher teacher) { this.teacher = teacher; }
-
@Resource:使用与 @Autowired 注解相同
-
@Qualifer:明确指定需要自动装配的 Bean 组件
@Qualifier("teacher2") //强制采用byName方式指定Bean的id
手动获取Bean的方式
Spring中,通过ApplicationContext手动获取Bean。
@Componet 默认id为类名(其首字母变为小写)
@Component //等价于 <bean id="teacher" class="bean.Teacher"> 配置 public class Teacher { private String name; private int age; }
初始化和销毁Ioc容器
//初始化(Ioc容器调用) public void init(){ System.out.println("调用初始化方法"); } //销毁(Ioc容器调用) public void destroy(){ System.out.println("调用销毁方法"); }
一些常用注解
初始化和销毁
通过@Bean(initMethod="init",destoryMethod="destory")方法
<bean id="boy" class="ioc.Boy" scope="singleton" init-method="init" destroy-method="destroy">
Java配置类
@Configuration
声明当前类为配置类;
@Bean
注解在方法上,声明当前方法的返回值为一个bean,替代xml中的方式;
@ComponentScan
用于对Component进行扫描;
@Bean的属性支持
@Scope设置类型:
设置Spring容器如何新建Bean实例(方法上,得有@Bean)
① Singleton
一个Spring容器中只有一个bean实例,默认模式
<bean id="boy" class="ioc.Boy" scope="singleton" init-method="init" destroy-method="destroy">
② Protetype
调用新建一个bean
<bean id="boy" class="ioc.Boy" scope="prototype" init-method="init" destroy-method="destroy">
③ Request
给每个http request新建一个bean
④ Session
给每个http session新建一个bean
⑤ GlobalSession
global http session新建一个Bean实例
@Value
支持如下方式的注入:
-
注入普通字符
-
注入操作系统属性
-
注入表达式结果
-
注入其它bean属性
-
注入文件资源
-
注入网站资源
-
注入配置文件
三种情况用法
-
${}找到外部配置参数并赋值
-
#{}是SpEL表达式,寻找对应变量内容
-
#{}将字符串的值注入
public class Student { @Value("Whaler") private String name; @Value("001") private int id; }
实例
Config
package bean.java; import org.springframework.context.annotation.Configuration; import javax.jws.soap.SOAPBinding; /* 配置类(Ioc)容器 */ @Configuration public class Config { @Bean public User user(){ return new User("12WL"); } }
TestBean
package bean.java; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class TestBean { public static void main(String[] args){ //通过注解方式加载Ioc容器 AnnotationConfigApplicationContext ioc = new AnnotationConfigApplicationContext(); //注册配置类 ioc.register(Config.class); //装配Bean ioc.refresh(); User user = ioc.getBean(User.class); System.out.println(user); } }
User
package bean.java; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor @AllArgsConstructor public class User { private String name; }
TestIoc
package ioc; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.context.support.FileSystemXmlApplicationContext; /** * @author 3DG * Ioc容器创建 */ public class TestIoc { public static void main(String[] args){ //加载Ioc容器方式一 ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("ioc.xml"); //加载Ioc容器方式二 // FileSystemXmlApplicationContext ioc2 = // new FileSystemXmlApplicationContext("E:\\Workout\\Spring001\\src\\main\\resources\\ioc.xml"); //获取Ioc容器的Bean实例(Boy对象实例) Boy boy =(Boy) ioc.getBean("boy");//bean的id System.out.println(boy.getGirl()); //Boy boy2 == ioc.getBean(Boy.class);要求boy类型唯一 Boy boy2 = (Boy)ioc.getBean("boy2"); System.out.println(boy2.getGirl()); Boy boy3 = (Boy)ioc.getBean("boy2"); System.out.println(boy); } }
bean_ioc.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" 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"> <!-- <default-autowire --> <!--开启自动装配注解(默认禁用注解)--> <context:annotation-config/> <!--开启自动扫描Bean--> <context:component-scan base-package="bean"/> <!--装配单例模式Bean factory-method用于调用单例模式的静态方法--> <bean id="earth" class="bean.Earth" factory-method="getInstance"/> <!--装配内部Bean--> <bean id="musician" class="bean.Musician"> <property name="name" value="朗朗"/> <property name="piano"> <bean class="bean.Piano"/> </property> </bean> <!--装配集合bean--> <bean id="chinese" class="bean.Subject" p:name="语文" p:score="66"/> <bean id="math" class="bean.Subject" p:name="数学" p:score="77"/> <bean id="english" class="bean.Subject" p:name="外语" p:score="88"/> <bean id="grade" class="bean.Grade"> <!--装配List集合--> <property name="subjects"> <list> <ref bean="chinese"/> <ref bean="math"/> <ref bean="english"/> </list> </property> <!--装配Set集合--> <property name="classNames"> <set> <value>"1班"</value> <value>"2班"</value> <value>"3班"</value> </set> </property> <!--装配Map集合--> <property name="numbers"> <map> <entry key="1班" value="35"/> <entry key="2班" value="37"/> <entry key="3班" value="36"/> </map> </property> </bean> <!--自动装配bean--> <!-- <bean id="teacher" class="bean.Teacher"> <property name="name" value="3DG"/> <property name="age" value="31"/> </bean> <bean id="teacher2" class="bean.Teacher"> <property name="name" value="Lu"/> <property name="age" value="35"/> </bean> --> <bean id="student" class="bean.Student" > <!--依赖注入的id(即byName的Name)是属性名--> <!-- <property name="name" value="Whaler"/> <property name="id" value="001"/> --> <!-- <property name="teacher" ref="teacher"/> --> </bean> </beans>