Spring入门到进阶 - Spring Bean管理 XML方式

Posted GreyBig

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring入门到进阶 - Spring Bean管理 XML方式相关的知识,希望对你有一定的参考价值。

Spring的工厂类介绍

public class SpringDemo1 {

    @Test
    /**
     * 传统方式开发
     */
    public void demo1(){
        // UserService userService = new UserServiceImpl();
        UserServiceImpl userService = new UserServiceImpl();
        // 设置属性:
        userService.setName("张三");
        userService.sayHello();
    }

    @Test
    /**
     * Spring的方式实现
     */
    public void demo2(){
        // 创建Spring的工厂
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 通过工厂获得类:
        UserService userService = (UserService) applicationContext.getBean("userService");

        userService.sayHello();
    }

    @Test
    /**
     * 读取磁盘系统中的配置文件
     */
    public void demo3(){
        // 创建Spring的工厂类:
        ApplicationContext applicationContext = new FileSystemXmlApplicationContext("c:\applicationContext.xml");
        // 通过工厂获得类:
        UserService userService = (UserService) applicationContext.getBean("userService");

        userService.sayHello();
    }

    @Test
    /**
     * 传统方式的工厂类:BeanFactory
     */
    public void demo4(){
        // 创建工厂类:
        BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
        // 通过工厂获得类:
        UserService userService = (UserService) beanFactory.getBean("userService");

        userService.sayHello();
    }

    /**
     * 传统方式的工厂类:BeanFactory
     */
    @Test
    public void demo5(){
        // 创建工厂类:
        BeanFactory beanFactory = new XmlBeanFactory(new FileSystemResource("c:\applicationContext.xml"));
        // 通过工厂获得类:
        UserService userService = (UserService) beanFactory.getBean("userService");

        userService.sayHello();
    }
}

resources/applicationContext.xml

<!-- UserService的创建权交给了Spring -->
<bean id="userService" class="com.imooc.ioc.demo1.UserServiceImpl">
    <property name="name" value="李四"/>
</bean>

Bean的实例化三种方式

resources/applicationContext.xml

<!--Bean的实例化的三种方式============================-->
<!--第一种:无参构造器的方式-->
<bean id="bean1" class="com.imooc.ioc.demo2.Bean1"/>
<!--第二种:静态工厂的方式-->
<bean id="bean2" class="com.imooc.ioc.demo2.Bean2Factory" factory-method="createBean2"/>
<!--第三种:实例工厂的方式-->
<bean id="bean3Factory" class="com.imooc.ioc.demo2.Bean3Factory"/>
<bean id="bean3" factory-bean="bean3Factory" factory-method="createBean3"/>

1、采用无参数的构造方法的方式

public class Bean1 {
    public Bean1(){
        System.out.println("Bean1被实例化了...");
    }
}
@Test
public void demo1(){
    // 创建工厂
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    // 通过工厂获得类的实例:
    Bean1 bean1 = (Bean1)applicationContext.getBean("bean1");
}

2、静态工厂实例化方式

public class Bean2 {

}
// Bean2的静态工厂
public class Bean2Factory {
    public static Bean2 createBean2(){
        System.out.println("Bean2Factory的方法已经执行了...");
        return new Bean2();
    }
}
@Test
public void demo2(){
    // 创建工厂
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    // 通过工厂获得类的实例:
    Bean2 bean2 = (Bean2)applicationContext.getBean("bean2");
}

3、实例工厂实例化

public class Bean3 {

}
// Bean3的实例工厂
public class Bean3Factory {
    public Bean3 createBean3(){
        System.out.println("Bean3Factory执行了...");
        return new Bean3();
    }
}
@Test
public void demo3(){
    // 创建工厂
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    // 通过工厂获得类的实例:
    Bean3 bean3 = (Bean3)applicationContext.getBean("bean3");
}

Bean的常用配置

1、一般情况下,装配一个Bean时,通过指定一个id属性作为Bean的名称,id属性在IOC容易中必须是唯一的,如果Bean的名称中含有特殊字符,就需要使用name属性
2、class用于设置一个类的完全路径名称,主要作用是IOC容器生成类的实例
Bean的作用域(scope属性):
1、singleton(默认值)在SpringIOC容器中仅存在一个Bean实例,Bean以单实例的方式存在;
2、prototype:每次调用getBean()时都会返回一个新的实例;
3、request:每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境;
4、session:同一个HTTP Session共享一个Bean,不同的HTTP Session使用不同的Bean。该作用域仅适用于WebApplicationContext环境

Spring容器中Bean的生命周期

Spring初始化bean或销毁bean时,有时需要做一些处理工作,因此Spring可以在创建和销毁bean的时候调用bean的两个生命周期方法

<bean id="abc" class="com.imooc.hello"
init-method="init"
destory-method="destory"
/>

当bean被载入到容器的时候调用init,当bean从容器中删除的时候调用destory(scope=singleton有效)

Bean的生命周期的完整过程

  1. instantiate bean对象实例化
  2. populate properties 封装属性
  3. 如果Bean实现BeanNameAware执行setBeanName
  4. 如果Bean实现BeanFactoryAware或者ApplicationContextAware 设置工厂
    setBeanFactory或者上下文对象setApplicationContext
  5. 如果存在类实现BeanPostProcessor (后处理Bean) , 执行postProcessBeforeInitialization
  6. 如果Bean实现InitializingBean执行afterPropertiesSet
  7. 调用< bean init-method= "init">指定初始化方法init
  8. 如果存在类实现BeanPostProcessor (处理Bean),执行
    postProcessAfterInitialization
  9. 执行业务处理
  10. 如果Bean实现DisposableBean执行destroy
  11. s调用< bean destroy-method= "customerDestroy">指定销毁方法
    customerDestroy

BeanPostProcessor的作用

resources/applicationContext.xml

<bean class="com.imooc.ioc.demo3.MyBeanPostProcessor"/>
<bean id="userDao" class="com.imooc.ioc.demo3.UserDaoImpl"/>
public class UserDaoImpl implements  UserDao {
    @Override
    public void findAll() {
        System.out.println("查询用户。。。");
    }
    @Override
    public void save() {
        System.out.println("保存用户。。。");
    }
    @Override
    public void update() {
        System.out.println("修改用户。。。");
    }
    @Override
    public void delete() {
        System.out.println("删除用户。。。");
    }
}
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        //System.out.println("第五步:初始化前方法...");
        return bean;
    }
    @Override
    public Object postProcessAfterInitialization(final Object bean, String beanName) throws BeansException {
        //System.out.println("第八步:初始化后方法...");
        if ("userDao".equals(beanName)) {
            Object proxy = Proxy.newProxyInstance(bean.getClass().getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    if ("save".equals(method.getName())) {
                        System.out.println("权限校验===================");
                        return method.invoke(bean, args);
                    }
                    return method.invoke(bean, args);
                }
            });
            return proxy;
        } else {
            return bean;
        }
    }
}
@Test
public void demo2(){
    ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    Man man = (Man)applicationContext.getBean("man");
    man.run();
    applicationContext.close();
}

结果:

技术图片

1、第一个proxy是Proxy.newProxyInstance得到的实例。而第二个proxy是InvocationHandler中的invoke方法的参数名。
2、这里的method属性传入的是Method类的对象,并不是一个名字。这个method对象是用真正的方法名,由方法名和形参抽象出Method对象。
3、args[]中传入的是原方法执行所需要的参数,由于参数可能有多个,所以使用数组。
4、这里不能返回this,invoke方法的返回值是代理类实例。this是当前对象的实例也就是InvocationHandler的实例。
5、method.invoke(o, args)方法,用来执行对象o的目标方法。在课程中的例子实际上就是那个UserDaoImpl对象的save方法。method.invoke方法的返回值是原方法的返回值。method.invoke方法的作用实际和直接“对象.方法名”调用作用是相同的
6、不能直接返回proxy对象。传入的参数proxy在我们重写的逻辑中没有直接用到,这只是父类中规定好的参数,我们重写时需要遵循。如果不return method.invoke就不会调用到想要调用的方法了。
因为我们增强时返回的是Proxy.newProxyInstance的实例,即外面的proxy代理对象。将来我们要使用它来进行调用,代理在调用的时候会自动调用invoke从而达到增强效果。如果不使用method.invoke就不会调用到真正的类的方法了。
如果同学还是不太理解,建议同学配合看一下后面的SpringAOP的 2-1 节JDK的动态代理课程

Spring的属性注入

对于类成员变量,注入方式有三种

  • 构造函数注入

  • 属性setter方法注入

  • 接口注入(不常用)

Spring支持前两种

构造方法注入

通过构造方法注入Bean的属性值或依赖的对象,它保证了Bean实例在实例化后就可以使用
构造器中注入在元素里声明的属性

<constructor-arg name="name" valve="张三">

set方法的属性注入

使用set方法注入,在Spring配置文件中,通过设置注入属性

第一种,value注入属性为普通类型的,如String,int型

<property name="" value="">

第二种,name为该类中的属性名,ref注入属性为对象的,值为其他bean的id或name

<property name="" ref="">

p名称空间的属性注入

  • 使用p命名空间

  • 为了简化XML文件配置,Spring从2.5开始引入一个新的p名称空间

  • 普通属性:p:属性名="xxx" 引入常量值

  • 属性为其他对象p:属性名-ref="xxx" 引用其它Bean对象

需要在xml配置文件中引入新头部xmlns:p="http://www.springframework.org/shema/p"

实例:

<bean id="person" class="com.imooc.ioc.demo4.Person" p:name="大黄" p:age="34" p:cat-ref="cat"/>
<bean id="cat" class="com.imooc.ioc.demo4.Cat" p:name="小黄"/>

Spring的属性注入-SqEL注入

(属性注入较为复杂时使用)

可以在#{.}里面调用其它类里面对应的方法

<property name="name" value="#{value}">
<property name="name" value="#{‘张三’}"/>
<property name="name" value="#{beanID.方法名()}">

SpEL表达式语言

语法:#{}

#{‘hello‘} : 使用字符串
#{beanId} : 使用另一个bean
#{beanId.content.toUpperCase()} : 使用指定名属性,并使用方法
#{T(java.lang.Math).PI} : 使用静态字段或方法

复杂类型的属性注入

<!--复杂类型的属性注入-->
<bean id="collectionBean" class="com.i.ioc.demo5.CollectionBean">
<!--数组类型-->
<property name="arrs">
    <list>
        <value>aaa</value>
        <value>ccc</value>
        <value>bbb</value>
    </list>
</property>
<!--List集合类型属性注入-->
<property name="list">
    <list>
        <value>111</value>
        <value>112</value>
        <value>113</value>
    </list>
</property>
<!--Set集合的属性注入-->
<property name="set">
    <set>
        <value>ddd</value>
        <value>eee</value>
        <value>fff</value>
    </set>
</property>
<!--Map集合的属性注入-->
<property name="map">
    <map>
        <entry key="aaa" value="123"></entry>
        <entry key="bbb" value="456"></entry>
        <entry key="ccc" value="789"></entry>
    </map>
</property>
<!--Properties的属性注入-->
<property name="properties">
    <props>
        <prop key="username">root</prop>
        <prop key="password">1234</prop>
    </props>
</property>
</bean>










以上是关于Spring入门到进阶 - Spring Bean管理 XML方式的主要内容,如果未能解决你的问题,请参考以下文章

Spring入门到进阶 - Spring AOP

Spring 从入门到精通系列 04——Spring 对 bean 的管理细节

Spring从入门到精通—Bean标签详解

5. Spring 通过 XML 配置 bean (进阶)

Spring从入门到精通—注解开发

Spring企业级程序设计 • 第2章 Spring Bean管理进阶