1 IOC概述
1.1 IOC概念
IOC中文是控制反转,即是某一接口具体实现类的选择控制权从调用类中移除,转交给第三方决定。从而解除了某一接口对实现类的直接依赖。
1.2 IOC类型
主要分为构造函数注入,属性注入,接口注入
构造函数注入
public class Bar {
private Foo foo;
public Bar(Foo foo) {
this.foo = foo;
}
}
属性注入
public class Bar {
private Foo foo;
public void setFoo(Foo foo) {
this.foo = foo;
}
}
接口注入
public interface BarInterface {
void setFoo(Foo foo);
}
public class Bar implements BarInterface {
private Foo foo;
public void setFoo(Foo foo) {
this.foo = foo;
}
}
此种方式和属性注入没有明显区别,但是却增加了一个接口,这不利于项目后期的维护,因此不建议使用!
1.3 spring的IOC配置
<?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="foo" class="org.acy.di.Foo"/>
<bean id="bar" class="org.acy.di.Bar">
<property name="foo" ref="foo"/>
</bean>
</beans>
2 spring的资源访问
2.1 资源抽象接口
Spring的Resource接口,使应用访问底层资源更加便捷。
主要方法:
-boolean exists() 是否存在
-boolean isOpen()
-URL getURL()
-File getFile()
-InputStream getInputStream()
这个接口下面主要的实现类有:
- ByteArrayResource:内存资源
- ClassPathResource:类路径下的资源
- FileSystemResource:文件系统资源
- InputStreamResource:输入流资源
- ServletContextResource:Web容器上下文资源
- UrlResource:远程资源
测试1
public class FileSourceExample {
public static void main(String[] args) {
String filePath = "C:\\Users\\Administrator\\IdeaProjects\\spring\\c03\\src\\main\\resources\\1.txt";
Resource resource1 = new FileSystemResource(filePath);
System.out.println(resource1.getFilename());
Resource resource = new ClassPathResource("1.txt");
System.out.println(resource.getFilename());
}
}
测试2
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%
Resource resource = new ServletContextResource(application, "/WEB-INF/classes/1.txt");
%>
<%=resource.getFilename()%>
<%=WebUtils.getTempDir(application).getAbsolutePath()%>
</body>
</html>
测试3
public class EncodedTest {
public static void main(String[] args) throws IOException {
Resource resource = new ClassPathResource("1.txt");
EncodedResource encodedResource = new EncodedResource(resource,"utf-8");
String s = FileCopyUtils.copyToString(encodedResource.getReader());
System.out.println(s);
}
}
注:资源加载时默认采用系统编码读取资源,如果需要转码,可用EncodedResource
2.2资源加载
资源地址表达式
- classpath: 从类的跟路径加载
- file: 从文件路径
- http: http协议
- ftp: ftp协议加载
- 没有前缀 则根据当前实用的ApplicationConext实现类决定
"classpath*:"相对于"classpath:"的优势在于:如果有同包名的资源文件,分别打成了两个jar包【a.jar和b.jar】。
用"classpath:"只加在a.jar中的资源文件。用"classpath*:"会加载a b两个jar包的配置文件
匹配符
? :一个字符
* :多个字符
** :多级目录
资源加载器
ResourceLoader:可以根据资源地址加载一个资源,但不支持匹配符
ResourcePatternResolver:支持匹配符
PathMatchingResourcePatternResolver:Spring的标准实现,也支持匹配符
public class ResolverTest {
public static void main(String[] args) throws IOException {
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource[] resources = resolver.getResources("classpath*:org/acy/**/*.xml");
for (Resource resource : resources) {
System.out.println(resource.getFilename());
}
}
}
3 BeanFactory与ApplicationContext
3.1 BeanFactory解读
BeanFactory是一个工厂,用于创造各种类型的对象。
BeanFactory体系结构
BeanFactory:底层接口
ListableBeanFactory:增加访问容器中Bean基本信息的方法 如bean的个数,是否包含等。
HierarchicalBeanFactory:父子容器级联接口,使子容器可以访问父容器。
ConfigurableBeanFactory:重要接口,增强了IOC的定���化,加入了类装载器、属性编辑器、容器初始化后置处理器的方法
AutowireCapableBeanFactory:加入自动装配
测试
public class BeanFactoryTest {
public static void main(String[] args) {
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource resource = resolver.getResource("classpath:applicationContext.xml");
BeanFactory beanFactory = new XmlBeanFactory(resource);
System.out.println("BeanFactory 初始化完成");
Car car = beanFactory.getBean("car", Car.class);
System.out.println(car);
}
}
注:以上使用了XmlBeanFactory,其为上面那些接口的最终实现类。用BeanFactory会导致Bean在容器启动时候不会主动初始化,而是等到第一次使用时候在初始化。
3.2 ApplicationContext介绍
主要实现类有ClasspathXmlApplicationContext与FileSystemXmlApplicationContext,且ApplicationContext所有实现类都实现了ResourcePatternResolver接口,可以接受匹配符表达式加载资源文件。
并且ConfigurableApplicationContext还加入了refresh()和close(),用于刷新和关闭容器。
ApplicationContext是在容器启动时初始化所有Bean
注解配置
@Configuration
public class Beans {
@Bean(name = "car")
public Car buildCar() {
Car car = new Car();
car.setBrand("三轮车");
car.setColor("red");
car.setMaxSpeed(200);
return car;
}
}
public class AnnoTest {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(Beans.class);
Car car = context.getBean("car", Car.class);
System.out.println(car);
}
}
WebApplicationContext
WebApplicationContext是存储在ServletContext中,所有可以再任何代码中取出实用。
WebApplicationContextUtils.getWebApplicationContext(ServletContext sc)
WebApplicationContext初始化
在Web.xml配置监听器
ContextLoaderListener
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
如果不支持Listener,则可以使用ContextLoaderServlet
以上配置,Spring会默认采用XmlWebApplicationContext,如果要采用注解,可以实用如下配置
<context-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>org.acy.anno.Beans</param-value>
</context-param>
4 Bean生命周期
Bean的作用范围
实例化Bean时所经历的一系列阶段
4.1 BeanFactory的生命周期
关键点:
- Bean自身的方法:如实例化,setter,或者init method和destroy method
- Bean级别生命周期接口方法: BeanNameAware BeanFactoryAware InitializingBean和DisposableBean
- 重点 容器级生命周期接口方法 InstantiationAwareBeanPostProcessor和BeanPostProcessor,这些接口的实现类为单独的组件,实现后注册到容器上即可。[属于插件机制]
可以注册多个同种接口的实现类,但是必须实现Ordered接口排序。
新版本中还加入了InstantiationAwareBeanPostProcessorAdapter抽象类
例子
public class Cat implements BeanFactoryAware,BeanNameAware,InitializingBean,DisposableBean {
private String brand;
private String color;
private int maxSpeed;
public Cat() {
}
public Cat(String brand, String color, int maxSpeed) {
this.brand = brand;
this.color = color;
this.maxSpeed = maxSpeed;
}
public void introduce() {
System.out.println(this.toString());
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getMaxSpeed() {
return maxSpeed;
}
public void setMaxSpeed(int maxSpeed) {
this.maxSpeed = maxSpeed;
}
@Override
public String toString() {
return "Car{" +
"brand='" + brand + '\'' +
", color='" + color + '\'' +
", maxSpeed=" + maxSpeed +
'}';
}
private BeanFactory beanFactory;
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("setBeanFactory");
this.beanFactory = beanFactory;
}
private String beanName;
public void setBeanName(String s) {
System.out.println("setBeanName");
this.beanName = s;
}
public void destroy() throws Exception {
System.out.println("destroy");
}
public void afterPropertiesSet() throws Exception {
System.out.println("afterPropertiesSet");
}
public void myInit(){
System.out.println("myInit");
this.setMaxSpeed(240);
}
public void myDestroy(){
System.out.println("myDestroy");
}
}
public class MyBeanPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if ("cat".equals(beanName)) {
Cat cat = (Cat) bean;
if (cat.getColor() == null) {
System.out.println("color 为空 设为黑色");
cat.setColor("black");
}
}
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if ("cat".equals(beanName)) {
Cat cat = (Cat) bean;
if (cat.getMaxSpeed() > 200) {
System.out.println("speed great then 200");
cat.setMaxSpeed(200);
}
}
return bean;
}
}
public class MyInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter {
@Override
public Object postProcessBeforeInstantiation(Class beanClass, String beanName) throws BeansException {
if ("cat".equals(beanName)){
System.out.println("postProcessBeforeInstantiation");
}
return null;
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
if ("cat".equals(beanName)){
System.out.println("postProcessAfterInstantiation");
}
return true;
}
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
if ("cat".equals(beanName)){
System.out.println("postProcessPropertyValues");
}
return pvs;
}
}
public class BeanCycle {
public static void main(String[] args) {
Resource res = new ClassPathResource("applicationContext.xml");
XmlBeanFactory beanFactory = new XmlBeanFactory(res);
ConfigurableBeanFactory configurableBeanFactory = beanFactory;
configurableBeanFactory.addBeanPostProcessor(new MyBeanPostProcessor());
configurableBeanFactory.addBeanPostProcessor(new MyInstantiationAwareBeanPostProcessor());
Cat cat = beanFactory.getBean("cat", Cat.class);
System.out.println(cat);
cat.setColor("yellow");
Cat c2 = beanFactory.getBean("cat", Cat.class);
System.out.println(cat == c2);
beanFactory.destroySingletons();
}
}
以上例子简单打印了一些spring的生命周期信息,并且有一些先后顺序。在新版本中 init method和destroy method的配置改为@PostConstruct和@PreDestroy注解配置。
BeanPostProcessor是一个扩展Spring的重要接口。
4.2 ApplicationContext的生命周期
加入了一个新接口ApplicationContextAware 用户注入ApplicationContext。
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinition beanDefinition = beanFactory.getBeanDefinition("cat");
beanDefinition.getPropertyValues().addPropertyValue("brand","奇瑞qq");
System.out.println("postProcessBeanFactory");
}
}
BeanFactoryPostProcessor实在最开始执行的,可以在对象实例化后,有线修改。在Bean被Spring加载后,会生成一个BeanDefinition
<bean id="cat" class="org.acy.bfc.Cat" init-method="myInit" destroy-method="myDestroy">
<property name="brand" value="奔驰"/>
<property name="color" value="黑色"/>
<property name="maxSpeed" value="200"/>
</bean>
<bean class="org.acy.bfc.MyBeanPostProcessor"/>
<bean class="org.acy.bfc.MyBeanFactoryPostProcessor"/>
此处配置了一些Processor,ApplicationContext在启动时候会自动加载这些Processor。