Java疯狂详解之Spring_装配Bean

来源:互联网 发布:美橙互联和阿里云 编辑:程序博客网 时间:2024/06/17 09:47

HelloSpring

  • IoC:控制反转
  • di:依赖(全局变量) 注入(set方法设置)
    我们自己类的全局变量 spring来替我们 通过set方法注入进去

装配Bean(基于XML)

常见的常见bean方式:
- 默认构造

<bean id="sbId" class=""/>
  • 工厂模式
    • 实例工厂(见struts和hibernate整合项目)
    • 静态工厂
      • 工厂方法是静态的 不需要创建工厂对象
        /**         *  工厂方法 大多数 返回值会是一个接口         *  根据不同的需求 产出该接口的不同实现         **/          public class StaticFactory {              public static Foo getFoo(){                  return new Foo();              }          }            /**              *  该方法 会先创建BeanFactory对象 再创建Foo对象              *  spring 调用方法 不需要关系权限修饰符              *  它是使用反射直接调用             **/          public class Foo {              public void fun(){                  System.out.println("fun方法被调用");              }          }          /**           *  如果我们在加载配置文件的时候不给路径           *  默认加载 applicationContext.xml(web工程)           **/          public void fun(){                  ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");                  Foo foo = (Foo) context.getBean("fooId");                  foo.fun();                  Foo foo2 = (Foo) context.getBean("foo2ID");                  foo2.fun();                  System.out.println(foo == foo2);                  /**                   *  默认构造方法                    *  静态工厂                   *  实例工厂                   *  注意: get出来的都是同一个对象 不管get多少次                  **/                  Foo foo3 = (Foo) context.getBean("foo                  Foo foo4 = (Foo) context.getBean("foo                  System.out.println(foo3==foo4);           } ```        -  实例工厂 与 静态工厂区别           - 需要先创建工厂对象 所提供的工厂方法全部是非静态的           - 例如 Struts + Hibernate 的项目工厂# Spring中Bean的种类在Spring中Bean分为两类- 普通Bean: 我们之前写的都是普通Bean- FactoryBean: 是一个特殊的Bean 它具有工厂生产的能力 只能生成特定的对象Bean 需要实现FactoryBean接口```xml<!--    使用spring 提供的接口 FactoryBean 实例化对象    class: 实现了 FactoryBean 接口的类--><bean id="fooFactoryBeanId" class="com.wlznb.test.factory.TestFactoryBean"/><div class="se-preview-section-delimiter"></div>
public class TestFactoryBean implements FactoryBean<Foo>{    //  泛型: 这个FactoryBean 要创建什么就写什么    @Override    public Foo getObject() throws Exception {        return new Foo();    }    @Override    public Class<?> getObjectType() {        return Foo.class;    }    /**     *  可以选择是否是单例对象(不是单例对象 意味着每次get出来 都是新的对象)    **/    @Override    public boolean isSingleton() {        return false;    }}        /**         *  使用spring 提供的接口 FactoryBean 实例化对象         *  接口 默认 false 不是单例对象 每次get出新对象        **/        Foo fooFactoryBean1 = (Foo) context.getBean("fooFactoryBeanId");        fooFactoryBean1.fun();        Foo fooFactoryBean2 = (Foo) context.getBean("fooFactoryBeanId");        fooFactoryBean1.fun();        System.out.println(fooFactoryBean1==fooFactoryBean2);<div class="se-preview-section-delimiter"></div>
  • 朴素的AOP
public class FooProxy extends Foo {    /**     *  AOP 面向切面思想     *  在调用方法 之前 之后 来插入调用方法      *  这样就可以影响 这个方法的 流程    **/    @Override    public void fun() {        System.out.println("fun方法调用之前--");        super.fun();        System.out.println("fun方法调用之后--");    }}public class TestFactoryBean implements FactoryBean<Foo>{    @Override    public Foo getObject() throws Exception {        return new FooProxy();    }    @Override    public Class<?> getObjectType() {        return FooProxy.class;    }    /**     *  可以选择是否是单例对象(不是单例对象 意味着每次get出来 都是新的对象)    **/    @Override    public boolean isSingleton() {        return false;    }}<div class="se-preview-section-delimiter"></div>

BeanFactory 和 FactoryBean 的对比

  • BeanFactory: 它是工厂 用户生成任意Bean的 我们自己创建的普通类
  • FactoryBean: 它是spring提供的一个特殊bean 用于生成一个特定的bean 例如可以生成一个普通bean的代理 来实现朴素的AOP效果

作用域

作用域: 用于指定spring创建的bean作用范围/实例个数

<!--    scope     通过指定scope属性     singleton(默认值) 整个项目无论调用多少次 getBean 只会有这一个对象    prototype(原型 多例的) 每次调用 getBean 都是新的对象--><bean id="testScopeID" class="com.wlznb.scope.TestScope" scope="prototype"/><div class="se-preview-section-delimiter"></div>
public class Main {    /**     *  @Test java单元测试 java unit     *     *  测试 Scope prototype    **/    @Test    public void fun(){        ApplicationContext context =                new ClassPathXmlApplicationContext                        ("com/wlznb/scope/scope.xml");        TestScope testScope1 = context.getBean("testScopeID", TestScope.class);        TestScope testScope2 = context.getBean("testScopeID", TestScope.class);        System.out.println(testScope1==testScope2);    }}

生命周期

构造方法 -> before -> init -> after
Spring可以指定调用JavaBean的生命周期方法

public class TestScope {    public TestScope(){        System.out.println("构造方法被调用");    }    public void sbinit(){        System.out.println("初始化");    }     public void sbDestroy(){        System.out.println("销毁");    }    public void fun(){        System.out.println("TestScope.fun");    }}public class Main {    /**     *  @Test java单元测试 java unit     *     *  测试 Scope prototype    **/    @Test    public void fun(){        /**         *  ApplicationContext 接口中没有 close方法         *  实现类 ClassPathXmlApplicationContext 中有close方法         *  测试的时候 需要scope使用 单例 否则spring 不知道你要创建多少个对象         *  *  单例时:            *  spring 只要你 加载了配置文件 就会把所有对象 初始化出来            *  存在 大map中 key就是id 使用的时候 就给取出来            *              *  多例时:            *  spring 不会给你创建对象 只有你使用的时候才会初始化对象        **/        ClassPathXmlApplicationContext context =                new ClassPathXmlApplicationContext                        ("com/wlznb/scope/scope.xml");        TestScope testScope1 = context.getBean("testScopeID", TestScope.class);        TestScope testScope2 = context.getBean("testScopeID", TestScope.class);        System.out.println(testScope1==testScope2);        context.close();    }    /**     *  反射调用方法    **/    try {        Method close = context.getClass().getMethod("close");        close.setAccessible(true);        close.invoke(context);    } catch (NoSuchMethodException e) {        e.printStackTrace();    } catch (IllegalAccessException e) {        e.printStackTrace();    } catch (InvocationTargetException e) {        e.printStackTrace();    }}
<!--    scope    通过指定scope属性    singleton(默认值) 整个项目无论调用多少次 getBean 只会有这一个对象    prototype(原型 多例的) 每次调用 getBean 都是新的对象--><bean id="testScopeID" class="com.wlznb.scope.TestScope"      scope="singleton"      init-method="sbinit" destroy-method="sbDestroy"/>
  • init-method: 当创建对象之后 立刻会被调用初始化方法
  • destroy-method: 当spring框架被关闭后 会调用销毁方法 该方法想要被调用:
    • 需要score为singleton
    • ApplicationContext对象手动关闭
      该接口没有close方法 但是我使用的实现类 ClassPathXmlApplicationContext有该方法
      或者使用反射 直接声明子类对象来调用close

Spring创建对象原理

当Spring加载配置文件后 会把整个配置文件中的所有 作用域为singleton的bean标签,全部实例化,
放入内部的一个Map中,当我们调用getBean的时候,
其实是从这个map中通过id来取出对象,如果配置成prototype,
那么Spring会在调用getBean的时候才去实例化对象,
并且不会维护它,即关闭Spring框架,也不会调用destroy方法

BeanPostProcessor接口

我们自己创建类实现接口 然后在配置文件中配置该类 即可实现 该配置文件中所有的bean对象
在init方法前后调用我们自己的方法 也是为AOP做准备
问题1: 该类能否被我们通过getbean拿到?
不能 实现该接口的类 只能卸载配置文件中
问题2: 该类是作用于一个对象 还是多个对象?
作用于配置文件中声明的 所有bean对象

属性注入

手动注入: 使用xml文件 用注解的形式注入

使用xml进行

构造方法注值

    <!--        对象的构造方法注入        如果bean对象通过构造方法 注入值        需要使用 constructor-arg 标签        index: 构造方法的第几个参数 从0开始        value: 注入的值(基本数据类型 和 String类型 直接用value)        name:  构造方法的形参名(常用)        type:  构造方法的参数类型 (很少用type 来指定参数 多个相同类型的 spring识别不出来你要注入哪个)        ref:   构造方法的参数 如果是一个对象使用该属性 并填入该对象bean标签的id值    -->    <bean id="userID" class="com.wlznb.inject.User">        <constructor-arg index="0" value="12"/>        <constructor-arg name="password" value="sb123"/>        <constructor-arg type="java.lang.String" value="bbb"/>    </bean>

set方法注值

使用 property 标签

    <bean name="addressID" class="com.wlznb.inject.CompanyAddress">        <property name="address" value="东莞"/>        <property name="salary" value="10000"/>    </bean>

集合属性注值

<bean id="testCollection" class="com.wlznb.inject.TestCollection">    <property name="arrData">        <array>            <value>小米</value>            <value>Java</value>            <value>脉动</value>        </array>    </property>    <property name="listData">        <list>            <value>吃饭</value>            <value>睡觉</value>            <value>写代码</value>        </list>    </property>    <property name="setData">        <set>            <value>丁丁</value>            <value>朋朋</value>        </set>    </property>    <property name="mapData">        <map>            <entry key="高富帅" value="嬲"/>            <entry>                <key><value>白富美</value></key>                <value></value>            </entry>            <entry key="男屌丝" value="挊"/>            <entry key="女屌丝" value="窊"/>        </map>    </property></bean>
//  测试 构造方法注值@Testpublic void fun(){    ApplicationContext context =            new ClassPathXmlApplicationContext                    ("com/wlznb/inject/inject.xml");    User user = context.getBean("userID",User.class);    System.out.println(user);    System.out.println("--- 测试 集合属性注值 ---");    TestCollection testCollection = context.getBean("testCollection", TestCollection.class);    String[] arrData = testCollection.getArrData();    System.out.println(Arrays.toString(arrData));    System.out.println(testCollection.getListData());    System.out.println(testCollection.getSetData());    System.out.println(testCollection.getMapData());}

http://blog.csdn.net/wanglongblog/