Spring基础
Ioc容器: 控制反转
控制:控制对象的创建及销毁(生命周期)
反转:将对象的控制权交给Ioc容器
约定
- 所有Bean的生命周期由IoC来管理
- 所有被依赖的Bean通过构造方法执行注入
- 被依赖的Bean需要优先创建
实现
- 实例化Bean
- 保存Bean
- 获取Bean
- 每个Bean有唯一ID与之匹配
import java.lang.reflect.constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import java.util.concurrentHashMap;
public class IoCContainer {
private Map<String, Object> beans = new ConcurrentHashMap<String, Object>
// 根据beanId获取获取一个bean
public Object getBean(String beanId) {
return beans.get(beanId);
}
/* 委托IoC创建一个bean
* @param clazz 要创建的bean的class
* @param beanId beaId
* @param paramBeanIds 要创建的bean的class的构造方法所需要参数的beanIds
public void setBean(Class<?> clazz, String beanId, String... paramBeanIds) {
// 1. 组装构造方法所需要的bean值
Object[] paramValues = new Object[paramBeanId.leangth];
for(int i=0; i<paramValues.leangth; i++) {
paramValues[i] = beans.get(i);
}
// 2. 调用构造方法实例化bean
Object bean = null;
for(Constructor<?> constructor : clazz.getConstructors()) {
try {
bean = constuctor.newInstance(paramValues);
} catch(InstantiationException e) {
} catch(IllegalAccessException e) {
} catch(InvocationTargetException e) {
}
if (bean == null) {
throw new RuntimeException("实例化bean失败!");
}
}
// 3. 将实例化的bean放入beans
beans.put(beanId, bean);
}
}
SpringIoC
引入spring核心包、上下文包、依赖
// pom.xml的配置,引入依赖
<dependencies>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.1.3.RELEASE</version>
</dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.3.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
创建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" >
<bean id="bean" class="...Bean" /> // ...Bean是Bean的路径
</beas>
获取Spring上下文
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
获取Bean
Bean bean = context.getBean("bean", Bean.class);
Spring Bean的相关用法
实例化Bean
通过构造方法实例化Bean
// 先获取上下文对象,在获取Bean
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
Bean bean = context.getBean("bean", Bean.class);
// 配置spring.xml
<bean class="...Bean" id="bean" />
- 通过静态方法实例化Bean
// 通过BeanFactory的静态方法获取Bean
public class BeanFactory {
public static Bean getBean() {
return new Bean();
}
}
// 获取Bean
Bean bean = BeanFactory.getBean();
// 配置spring.xml
<bean class="...BeanFactory" factory-method="getBean" id="beanFromFactory" />
通过实例方法实例化Bean
// 通过BeanFactory一般方法获取Bean
public class BeanFactory {
public Bean getBean() {
return new Bean();
}
}
// 获取Bean
BeanFactory beanFactory = new BeanFactory();
Bean bean = new beanFactory.getBean();
// 配置spring.xml
<bean class="...BeanFactory" id="beanFactory" />
<bean class="...Bean" factory-bean="baenFactory" factory-method="getBean" id="beanFromFactory" />
Bean的别名
// 配置多个别名
<bean class="...Bean" id="bean1" name="bean2, bean3" />
Bean bean1 = context.getBean("bean1", Bean.class); // 实例化bean1
Bean bean2 = context.getBean("bean2", Bean.class); // 实例化bean2,注意:bean2与bean1是同一个bean
// 为已经实例化的bean起别名
<alias name="bean1" alias="bean3" />
注入Bean
通过构造方法注入Bean
public class Bean {
private AnotherBean anotherBean;
private String string;
public Bean(AnotherBean anotherBean, String string) {
this.anotherBean = anotherBean;
this.string = string;
}
// 除了构造方法,还有各个属性的get、set方法......
}
// spring.xml的配置
<bean class="...AnotherBean" id="anotherBean" />
<bean class="...Bean" id="bean">
/* index指明构造方法的第几个属性(与name、type没必要全部写出,只要指明属性就行)
* name属性名称
* type类名(完整路径)
* value属性值,用于基本类型
* ref属性值,用于复合类型
<construcor-arg index="0" name="anotherBean" type="...AnotherBean" ref="anotherBean" />
<construcor-arg index="1" name="string" type="java.lang.String" value="abcde" />
</bean>
// 简单写法,须在头增加一些信息
xmlns:c="http://www.sprinframework.org/schema/c"
<bean class="...Bean" id="bean" c:anotherBean-ref="anotherBean" c:string="abcde" />
通过set方法注入Bean
// spring.xml的配置
<bean class="...AnotherBean" id="anotherBean" />
<bean class="...Bean" id="bean">
<property name="anotherBean" ref="anotherBean" />
<property name="string" value="abcde" />
</bean>
// 简单写法,须在头增加一些信息
xmlns:p="http://www.sprinframework.org/schema/p"
<bean class="...Bean" id="bean" p:anotherBean-ref="anotherBean" p:string="abcde" />
集合类型Bean的注入
public class Bean {
private List<String> stringList;
private Map<String, anotherBean> anotherBeanMap;
// 还有get、set方法......
}
// spring.xml的配置
<bean class="...AnotherBean" id="anotherBean" />
<bean class="...Bean" id="bean">
<property name="stringList">
<list>
<value>abcde</value> // <ref bean="anotherBean">
</list>
</property>
<property name="anotherBean">
<map>
<entry key="a" value-ref="anotherBean" /> // key / key-ref / value / value-ref
</map> // <set><ref bean="anotherBean"></set>
</property>
</bean>
null值注入
<bean class="...Bean" id="bean">
<property>
<null/>
</property>
</bean>
注入时创建Bean
// spring.xml的配置
<bean class="...AnotherBean" id="anotherBean" />
<bean class="...Bean" id="bean">
<property name="anotherBean" ref="anotherBean" />
<property name="string" value="abcde" />
</bean>
// 可以写成如下(注入时创建Bean)
<bean class="...Bean" id="bean">
<property name="anotherBean">
<bean class="...AnotherBean" id="anotherBean" />
</property>
</bean>
Bean作用域
Singleton作用域(单例模式)
// 在同一个上下文环境(context)请求同类型的Bean都会返回同一个bean,不同上下文单例模式失效
<bean class="...Bean" id="bean" scope="singleton" />
prototype作用域(多例模式)
// 同一个上下文环境得到不同bean
<bean class="...Bean" id="bean" scope="prototype" />
Web环境作用域
// 准备工作:建立SpringWeb环境
<servlet>
<servlet-name>SpringServlet</servlet-name>
<servlet-class>org.springframeword.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>SpringServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
// 如果不使用DispatcherServlet,则需要增加listener或filter
<listener> // Servlet2.4以上
<listener-class>
org.springframeword.web.context.request.RequestContextListener
<listener-class>
</listener>
// 准备bean类
@Controller
public class RequestControler {
@RequestMapping("testRequest")
@ResponseBody
public String static() {
return this.toString();
}
}
@Controller
public class SessionControler {
@RequestMapping("testSession")
@ResponseBody
public String static() {
return this.toString();
}
}
@Controller
public class ApplicationControler {
@RequestMapping("testApplication")
@ResponseBody
public String static() {
return this.toString();
}
}
// request作用域:每次请求会获得新的实例
<bean class="...RequestController" scope="request" />
// session作用域:同一sesiion下获得同一实例,不同session则获得新实例
<bean class="...SessionController" scope="session" />
// application作用域
<bean class="..ApplicationController" scope="application" />
自定义作用域
// 自定义双例模式
public class MyScope implements Scope {
private Map<String, Object> map1 = new ConcurrentHashMap<String, Object>();
private Map<String, Object> map2 = new ConcurrentHashMap<String, Object>();
// 实现Scope接口的方法:get()、remove()等
public Object get(String name, ObjectFactory<?> ObjectFactory) {
if (!map1.containsKey(name)) {
Object o = objectFactory.getObject();
map1.put(name, o);
return o;
}
if (!map2.containsKey(name)) {
Object o = objectFactory.getObject();
map2.put(name, o);
return o;
}
int i = new Random().nextInt(bound 2);
if (i ==0 ) {
return map1.get(name);
} else {
return map2.get(name);
}
}
public Object remov(String name) {
if (map2.containsKey(name)) {
Object o = map2.get(name);
map2.remov();
return o;
}
if (map1.containsKey(name)) {
Object o = map1.get(name);
map1.remov();
return o;
}
return null;
}
}
// 配置spring.xml
<bean class="...MyScope" id="myScope" />
<bean class="org.springframework.bean.factory.config.CustomScopeConfigurer">
<property name="scope">
<map>
<entry key="myScope" value-ref="myScope" />
</map>
</property>
</bean>
<bean class="...Bean" id="bean" scope="myscope" />
// 自定义线程作用域:在同一线程下得到同一实例,不同线程下得到不同实例
<bean class="...MyScope" id="myScope" />
<bean class="org.springframework.context.suppor.SimpleThreadScope" id="simpleThreadScope" />
<bean class="org.springframework.bean.factory.config.CustomScopeConfigurer">
<property name="scope">
<map>
<entry key="myScope" value-ref="myScope" />
<entry key="simpleThreadScope" value-ref="simpleThreadScope" />
</map>
</property>
</bean>
<bean class="...Bean" id="bean" scope="simpleThreadScope" />
Bean的懒加载
懒加载:多例模式下在context初始化时没有创建Bean,使用context.getBeans()才会实例化Bean
单例模式下在context上下文初始化时Bean已经被加载,多例模式可以在spring.xml文件中设定
// 为某个Bean设定懒加载
<bean class="...Bean" id="bean" lazy-init="true" />
// 为所有的Bean设定懒加载
<beans ... default-lazy-init="true">
......
</beans>
Bean初始化及销毁逻辑处理
init-method: Bean在初始化后执行某一方法
destroy-method: Bean在销毁之前执行某一方法
// 加入Bean里有onInit()和onDestroy()方法
<bean class="...Bean" id="bean" init-method="onInit" destroy-method="onDestroy" />
// 另一种方式,为所有Bean设定初始化和销毁逻辑处理
<beans ...
default-init-method="onInit"
default-destroy-method="onDestroy">
......
</beans>
// 也可以通过实现InitializingBean和DisponsableBean接口的方式实现,需要实现相关方法
Bean属性继承
// 假定有Class1、Class2继承于ParentClass,attrbute1~3
<bean class="...Class1" id="class1">
<property name="attrbute1" value="attrbute1" />
<property name="attrbute2" value="attrbute2" />
<property name="attrbute3" value="attrbute3" />
<property name="attrbute4" value="attrbute4" />
</bean>
<bean class="...Class2" id="class2">
<property name="attrbute1" value="attrbute1" />
<property name="attrbute2" value="attrbute2" />
<property name="attrbute3" value="attrbute3" />
<property name="attrbute5" value="attrbute5" />
</bean>
// 简化代码
<bean class="...ParentClass" id="parentClass" abstract="true"> // abstract说明不需要实例化该方法
<property name="attrbute1" value="attrbute1" />
<property name="attrbute2" value="attrbute2" />
<property name="attrbute3" value="attrbute3" />
</bean>
<bean class="...Class1" id="class1" parent="parentClass">
<property name="attrbute4" value="attrbute4" />
</bean>
<bean class="...Class2" id="class2" parent="parentClass">
<property name="attrbute5" value="attrbute5" />
</bean>
// 如果Class1、Class2不是继承于ParentClass,并且有自己的attrbute1~3
<bean id="parentClass" abstract="true"> //删掉 class="...ParentClass"
<property name="attrbute1" value="attrbute1" />
<property name="attrbute2" value="attrbute2" />
<property name="attrbute3" value="attrbute3" />
</bean>
<bean class="...Class1" id="class1"> // 删掉parent="parentClass"
<property name="attrbute4" value="attrbute4" />
</bean>
<bean class="...Class2" id="class2">
<property name="attrbute5" value="attrbute5" />
</bean>
SpringIoC注解
获取Bean
// 创建一个class配置文件
@Configuration
public class MyConfiguration {
// 将一个Bean交由Spring创建并管理
@Bean("bean1")
public Bean bean1() {
return Bean1 = new Bean1();
}
}
// 获取Spring上下文
ApplicationContext context = new AnnotationConfigApplicationContext(BeanConfiguration.class);
// 获取Bean
Bean1 bean1 = context.getBean("bean1", Bean.class);
// 简化写法
@Configuration
@ComponentScan(value="...package")
public class MyConfiguration {
}
// 开启包扫描
<beans ......>
<context:component-scan base-package="...package" />
</beans>
// Bean设置
@Component(value="bean") // 通过构造方法实例化bean,并通过value指定了bean的id
public class Bean {
}
// 其他注解也可以实现类似功能
@Controller: 被标注在Controller层
@Service: 被标注在Service层
@Request: 被标注在Dao层
@conponent: 通用型注解
注入Bean
通过方法注入Bean(构造方法、set方法)
// 1、MyBean类、构造方法或set方法
@Component
public class MyBean {
private AnotherBean anotherBean;
@Autowired
public MyBean( AnotherBean anotherBean) {
this.anotherBean = anotherBean;
}
}
// 2、AnotherBean类
@Component
public class AnotherBean {
}
// 3、Spring上下文环境(Configuration类)
@Configuration
@ComponentScan(value="...package")
public class MyConfiguration{
}
通过属性注入
// 环境同上
@Component
public class MyBean {
@Autowired
private AnotherBean anotherBean;
}
集合类Bean的型注入
// MyBean类、环境同上
@Component
public class MyBean {
private List<String> stringList; // Map一样
@autowired
public void setStringList(List<String> stringList) {
this.stringList = stringList;
}
}
// MyConfiguration类
@Configuration
@ComponentScan("...package") // 须在spring.xml开启包扫描
public class MyConfiguration {
@Bean // 注入时指定id:@Bean("stringList") --> @Qualifier("stringList") ,优先级高
public List<String> stringList() {
List<String> list = new ArrayList<String>();
list.add("111");
list.add("222");
return list;
}
// 另外一种方式:spring为类属性自动匹配对应泛型的注入,优先级高于第一种方式
@Bean
@Order(1) // Order指定在List里的顺序
public String stirng1() {
return "111";
}
}
String、Integer等类型直接赋值
@Component
public class MyBean {
@Value("11111")
private String string;
public void setString(String string) {
this.string = string;
}
}
SpringIoC容器内置接口实例注入
@Conponent
public class MyBean {
private ApplicationContext context;
@autowired // 可以直接在Bean中直接使用context
public void setContext(ApplicationContext context) {
return context;
}
}
// 可以直接在Bean中直接使用context
ApplicationContext context = new AnnotationConfigApplicationMyConfiguration(MyConfiguration:class);
MyBean myBean = context.getBean(name:"myBean", MyBean.class);
AnotherBean anotherBean = myBean.getContext().getBean(name:"anotherBean", AnotherBean);
设置Bean的作用域
// 第一种方法
@Component
@Scope("singleton")
public class Bean {
}
// 第二中方式
@Configuration
@ComponentScan("...backage")
public class BeanConfiguration {
@Bean
@Scope("singleton")
public Bean bean() {
return Bean = new Bean();
}
}
// 注解方式实现自定义作用域
// 定义自己的作用域
public class MyScope implements org.springframework.beans.factory.config.Scope {
@Override
public Objeect get(String s, ObjectFactory<?> objectFactory) { ... }
@Override
public Objeect remove(String s) { ... }
}
// 配置
@Configuration
@ComponentScan("...backage")
public class BeanConfiguration {
@Bean
public MyScope myScope() { return new MyScope(); }
@Bean()
public CustomScopeConfigurer customScopeConfigurer(MyScope myScope) {
CustomScopeConfigurer configurer = new CustomScopeConfigurer();
configurer.addScope("myScope", myScope);
return configurer;
}
@Bean
@Scope("myScope")
public Bean bean() { return Bean = new Bean(); }
}
开启Bean的懒加载
@Configuration
@Lazy // 第一种方式
public class BeanConfiguration {
@Bean
@Lazy // 第二种方式
public MyScope myScope() { return new MyScope(); }
}
Bean的初始化和懒加载
// 第一种方式,接口方式
public class Bean implements InitializingBean, DisposableBean {
@Override
public void afterPropertiesSet() { ... }
@Override
public void destroy() { ... }
}
// 第二种方式
public class Bean {
public void onInit() { ... }
public void onDestroy() { ... }
}
@Configuration
public class BeanConfiguration {
@Bean(initMethod="onInit", desdroyMethod="onDestroy")
public Bean bean() {
return new Bean();
}
}