Spring IOC 配置详解

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.jarb.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。

猜你喜欢

转载自www.linuxidc.com/Linux/2017-03/141257.htm