转载

Spring简介及xml配置

Java Web发展史

  • 第一阶段: JavaBean + Servlet + Jsp 逐步发展
  • 第二阶段:面对 EJB 重量级框架带来的种种麻烦
  • 第三阶段: SpringMVC / Struts + Spring + Hibernate / myBatis
  • 第四阶段:享受 SpringBoot "约定大于配置"的种种乐趣,很多繁琐的配置都变成了约定
  • 第五阶段:以 Dubbo 为代表的 SOA 为服务架构体系(Dubbo是阿里创建的)
  • 第六阶段:比较前沿的技术, SpringCloud 微服务架构技术生态圈(基于SpringBoot,保证了开箱即用,需要什么SpringCloud都有)

IoC 控制反转

不只是 SpringIoC ,其他的框架也具有相同的IoC思想及应用:

控制
反转

IoC容器约定

①所有 Bean 的生命周期交由 IoC容器 管理

②所有 被依赖的Bean 通过构造方法执行注入

被依赖的Bean 需要优先创建

Spring IoC容器使用方法

概述

通过 Spring.xml 文件实例化 Bean .只要 Spring.xml 中配置了 bean 标签,则就会根据 class 创建这个 bean 的实例.

把一个java bean交给Spring管理步骤:

1、创建一个xml格式的配置文件

2、在xml文件中定义一个bean,给每个bean设定一个id

3、通过ApplicationContext获取Spring上下文

ApplicationContext context = new ClassPathXmlApplicatioinContext("文件名.xml");

4、获取bean

Bean bean = context.getBeal("第一步中给bean的id",Bean.class);

1、通过 构造方法 实例化Bean

步骤1:创建要实例化的类,并提供无参构造方法。

public class Bean {
    public Bean(){
        System.out.println("Bean被创建了");
    }

步骤2: spring.xml 中配置

<bean id="bean的唯一标识" class="要实例化bean的路径"></bean>

测试:

ApplicationContext context=new ClassPathXmlApplicationContext(spring.xml的路径);
Bean bean=context.getBean("bean",Bean.class);
System.out.println(bean);

2、通过 静态工厂 方法实例化Bean

通过 Bean2 的工厂的静态方法实例化 Bean .

步骤1:创建 Bean2 的工厂 Bean2Factory 类以及 Bean2 类,并且提供一个静态、返回值类型为 Bean2 的方法,返回 new Bean2()

public class Bean2Factory {
    public static Bean2 getBean2(){
        return new Bean2();
    }
}

public class Bean2 {
    public Bean2(){
        System.out.println("Bean2被创建了。");
    }

步骤2:配置 Spring.xml

<bean class="Bean2工厂的路径" factory-method="Bean2工厂的静态方法名" id="Bean2工厂的唯一标识"></bean>

测试:

ApplicationContext context=new ClassPathXmlApplicationContext("spring-ioc2.xml");
Bean2 bean=context.getBean("bean2factoryId",Bean2.class);
System.out.println(bean);

3、通过 实例工厂 方法实例化Bean

通过 Bean3 的工厂的实例方法实例化 Bean .

步骤1:创建 Bean3 的工厂 Bean3Factory 类以及 Bean3 类,并且提供一个返回值类型为 Bean3 的方法,方法返回 new Bean3()

public class Bean3Factory {
    public  Bean3 getBean3(){
        return new Bean3();
    }
}

public class Bean3 {
    public Bean3(){
        System.out.println("Bean3被创建了。");
    }
}

步骤2:配置 Spring.xml

<bean class="main.java.com.imooc2.Bean3Factory" id="bean3Factory"></bean>
<bean class="main.java.com.imooc2.Bean3" factory-bean="bean3Factory" factory-method="getBean3" id="bean3"></bean>

给bean取别名

有类 Bean1 ,并且通过 bean 标签实例化 Bean1 ,可以给 Bean1 的实例取多个名字。

方式一: bean标签里添加name属性

<bean id="bean" class="main.java.com.imooc1.Bean" name="bean1_1,bean1_2"></bean>

方式二: 添加<alias>标签

<bean id="bean" class="main.java.com.imooc2.Bean1" name="bean1_1,bean1_2"></bean>
<alias name="bean" alias="bean1_3"/><!-- alias只支持一个别名 -->

依赖注入的方式

Spring简介及xml配置

1.通过 构造方法 注入Bean

Spring简介及xml配置

简化写法:

Spring简介及xml配置

2.通过 Set()方法 注入Bean

Spring简介及xml配置

3. 集合类型 注入Bean

Spring简介及xml配置

Spring简介及xml配置

4.注入 null 空值

Spring简介及xml配置

5.注入内部 bean

Spring简介及xml配置

Spring中Bean的作用域

1、 Singleton 作用域(单例模式)

通过Spring容器实现单例模式,具有局限性:保证在一个Spring上下文( ApplicationContext )是单例模式,多个 AppliactionContext 单例模式就失效了。

Spring简介及xml配置

2、 prototype 作用域(多例模式)

如果一个<bean>的作用域为prototype,则该<bean>会被实例化多次,有多个Bean会被创建(每次向Spring上下文请求该Bean都会new一个新的实例)。

Spring简介及xml配置

Bean1依赖Bean2,总结起来:

Spring简介及xml配置

对于蓝框中的情况,有时候我们需要单个Bean1,多个Bean2,就要用到方法注入.

方法注入

Spring简介及xml配置

Bean2代码修改:

Spring简介及xml配置

Spring.xml修改:

Spring简介及xml配置

这样即使Bean1是单例模式,每次拿到Bean1都会是不同的Bean2实例.

3、 Web环境 作用域

request 作用域、 session 作用域、 application 作用域、 websocket 作用域(使用较少).....

request:每次浏览器刷新都会实例化一个新的bean;

session:浏览器刷新不会实例化新的bean,更换浏览器则会实例化新的bean;

application:bean实例化之后就不会改变,更换浏览器也不会。

SpringWeb上下文环境

在web.xml中定义:

Spring简介及xml配置

不使用DispatcherServlet:

Spring简介及xml配置

Spring简介及xml配置

以RequestController为例:

Spring简介及xml配置

在spring.xml中添加:

Spring简介及xml配置

  • request:每次浏览器刷新都会实例化一个新的bean;
  • session:浏览器刷新不会实例化新的bean,更换浏览器则会实例化新的bean;
  • application:bean实例化之后就不会改变,更换浏览器也不会。

Spring简介及xml配置

4、 自定义 作用域

Spring内置的自定义 SimpleThreadScope 作用域 以自定义 双例模式

为例:

步骤1:实现Scope接口

(org.springframework.beans.factory.config.Scope)主要关注实现的get方法和remove方法。

Spring简介及xml配置

get() 方法:按照name参数,按照我们自己定义的规则,去返回一个Bean,如果我们定义的规则里,Bean不存在,那么将通过objectFactory去创建一个Bean。

双例模式:一个bean的Id对应两个实例,实现双例模式,需要两个Map集合,Map<String,Object> map1=new HashMap<String,Object>();Map<String,Object> map2=new HashMap<String,Object>();。

get()方法:

public Object get(String name, ObjectFactory<?> objectFactory) {
        if(!map1.containsKey(name)){   //判断map1是否包含名为name的Bean实例
            Object o=objectFactory.getObject();//如果不存在则创建一个ObjectFactory规则Bean
            map1.put(name, o);   //并把这个Bean放入集合,并命名为name
            return o;
        }
        if(!map2.containsKey(name)){   //map2同map1操作
            Object o=objectFactory.getObject(); 
            map2.put(name, o);  
            return o;
        }

//如果map1和map2都包含这个Bean,也就是说Spring上下文通过Id获取有两个实例,则返回一个0或1
        int i=new Random().nextInt(2);
        if(i==0){
            return map1.get(name);//如果是0,则返回对象1
        }else{
            return map2.get(name);//如果是0,则返回对象2
        }
    }

remove() 方法:和get方法相反,按照name参数,去移除一个Bean。

public Object remove(String name) {
        if(map1.containsKey(name)){
            Object o=map1.get(name);
            map1.remove(name);
            return o;
        }
        if(map2.containsKey(name)){
            Object o=map2.get(name);
            map2.remove(name);
            return o;
        }
        return null;    //说明没拿到任何实例
    }

步骤2: spring.xml配置

<bean id="myScope" class="main.java.com.自定义作用域.MyScope"></bean>

<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
    <property name="scopes">
        <map>
            <entry key="myscope" value-ref="myScope"></entry>
        </map>
    </property>
</bean>

测试

@Test
public void testBean(){
        ApplicationContext ac=new ClassPathXmlApplicationContext("spring-zidingyi.xml");
        for(int i=0;i<10;i++){
            Bean bean=ac.getBean(“myScope”", Bean.class);
            System.out.println(bean);
        }
    }

补充: SimpleThreadScope

Spring提供的 线程内单例 作用域:

  • 同一线程中Spring上下文会分配同一实例
  • 不同线程(Thread)中,则获得不同实例。

srping配置:

<bean id="myScope" class="main.java.com.自定义作用域.MyScope" ></bean>
<bean id="simpleThreadScope" class="org.springframework.context.support.SimpleThreadScope"></bean>

<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
    <property name="scopes">
        <map>
        <entry key="myscope" value-ref="myScope"></entry>
        <entry key="simpleThreadScope" value-ref="simpleThreadScope"></entry>
        </map>
    </property>
</bean>

<bean id="bean11" class="main.java.com.自定义作用域.Bean" scope="simpleThreadScope"></bean>

测试代码:

public void testBean(){
        final ApplicationContext ac=new ClassPathXmlApplicationContext("spring-zidingyi.xml");

        for(int i=0;i<10;i++){
        new Thread(new Runnable(){
            @Override
            public void run() {
                    Bean bean=ac.getBean("bean11", Bean.class);
                    System.out.println(bean);
            }
        }).start();
    }
    }
}

默认Scope(单例)Bean的懒加载

Spring容器会在创建容器时提前初始化 Singleton 作用域的bean,但是如果Bean被标注了 lazy-init=“true” ,则该Bean只有在其被需要的时候才会被初始化。(只对singleton作用域的bean有效)

<bean id="bean" class="main.java.com.Bean懒加载.Bean" scope="singleton" lazy-init="true"></bean>

多个bean使用懒加载:

<beans default-lazy-init=“true”></beans>

表示spring配置文件里所有bean都是懒加载模式。

使用场景:

如果某个Bean在程序整个运行周期都可能不会被使用,那么可考虑设定该Bean为懒加载。

  • 优点:尽可能的节省了资源。
  • 缺点:可能会导致某个操作相应操作时间增加。

Bean初始化及销毁

以singleton作用域为例,假设有一个javaBean,该Bean的作用是连接数据库,该Bean被创建之后,执行数据库连接操作.

Bean初始化

如果需要在Bean实例化时执行一些逻辑,Spring提供了两种方法:

init-method
InitializingBean

Bean销毁

如果需要在Bean销毁之前执行一些逻辑,有两种方法。

destory-method
DisposableBean

案例1:

通过bean标签的init-method和destory-method属性来指定Bean初始化逻辑和销毁逻辑。

代码:

public class Bean {
    public void onInit(){
        System.out.println("Bean的初始化逻辑方法被执行了");
    }
    public void onDestory(){
        System.out.println("Bean的销毁逻辑方法被执行了");
    }
}

spring.xml配置:

<bean class="main.java.com.Bean初始化及销毁.Bean" 
      id="bean" 
      init-method="onInit" 
      destroy-method="onDestory"/>

测试代码:

@Test
public void test(){
        ApplicationContext ac=new ClassPathXmlApplicationContext("spring-initAnddestory.xml");
        Bean bean=ac.getBean("bean", Bean.class);
        System.out.println(bean);
    }

结果:bean的销毁方法没执行,因为当前是单例模式,所以Bean的初始化是在Spring上下文实例化完成的,Bean的销毁是在Spring上下文的销毁过程中执行Bean的销毁。(Spring上下文的销毁定义到AbstractApplicationContext中)

改进:

@Test
public void test(){
        AbstractApplicationContext ac=new ClassPathXmlApplicationContext("spring-initAnddestory.xml");
        Bean bean=ac.getBean("bean", Bean.class);
        System.out.println(bean);
        ac.close();
}

注意:如果所有的Bean都有相同名称的初始化方法和相同名称的销毁方法,可以在spring.xml中定义:

<beans default-init-method="onInit"   
       default-destory-method="onDestory"/>

案例2:

实现相应接口,并实现相应方法

代码:

public class Bean implements InitializingBean,DisposableBean{
    @Override
    public void destroy() throws Exception {
        System.out.println("Bean的销毁逻辑方法被执行了");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("Bean的初始化逻辑方法被执行了");
    }
}

spring.xml配置:

<bean class="main.java.com.Bean初始化及销毁.Bean" id="bean"></bean>

Bean属性继承

应用场景

场景1:

ParentClass(属性1,属性2,属性3,get和set方法)
子类1(属性4,属性5) 
子类2(属性6,属性7)

场景2:

子类1和子类2没有父类,而是有一些相同的属性。

类1:(属性1,属性2,属性3,属性4,属性5)
类2:(属性1,属性2,属性3,属性6,属性7)

这两个场景下,通过Spring注入类1和类2的所有属性,一般如下:

  • abstract="true" :设置 <bean> 标签只是定义性的,不会对它进行实例化操作。
  • parent属性 :在Bean的子类bean标签添加,值为父类的Id。

场景1:

spring.xml配置:

<bean id="bean" class="main.java.com.Bean继承属性.ParentClass" abstract="true">
<property name="attribute1" value="attribute1"></property>
<property name="attribute2" value="attribute2"></property> 
<property name="attribute3" value="attribute3"></property>
</bean>

<bean id="bean1" class="main.java.com.Bean继承属性.Class1" parent="bean">
<property name="attribute4" value="attribute4"></property>
<property name="attribute5" value="attribute5"></property>
</bean>   

<bean id="bean2" class="main.java.com.Bean继承属性.Class2" parent="bean">
<property name="attribute6" value="attribute6"></property>
<property name="attribute7" value="attribute7"></property>
</bean>

场景2:

类1和类2不继承某一父类,只是存在相同属性。

spring.xml配置:

<bean id="bean" abstract="true">
<property name="attribute1" value="attribute1"></property>
<property name="attribute2" value="attribute2"></property> 
<property name="attribute3" value="attribute3"></property>
</bean>

<bean id="bean1" class="main.java.com.Bean继承属性.Class1" parent="bean">
<property name="attribute4" value="attribute4"></property>
<property name="attribute5" value="attribute5"></property>
</bean>   

<bean id="bean2" class="main.java.com.Bean继承属性.Class2" parent="bean">
<property name="attribute6" value="attribute6"></property>
<property name="attribute7" value="attribute7"></property>
</bean>
原文  https://segmentfault.com/a/1190000021494833
正文到此结束
Loading...