zoukankan      html  css  js  c++  java
  • spring IOC 详解

    Hello World

    wKioL1QDH7Ozya2jAAEfLCtXWVM593.jpg

    HelloWorld.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    package com.test.spring01;
     
    public class HelloWorld {
        private String name;
     
        public HelloWorld() {
            System.out.println("调用构造函数...");
        }
     
        public String getName() {
            return name;
        }
     
        public void setName2(String name) {//对应name="name2" 
            this.name = name;
        }
     
        public void sayHello() {
            System.out.println("Hello," + name);
        }
     
    }

    Main.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    package com.test.spring01;
     
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
     
    public class Main {
        public static void main(String[] args) {
        //ClassPathXmlApplicationContext是ApplicationContext接口的实现类,实现从类路径下加载配置文件
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext("ApplicationContext.xml");
            System.out.println("创建对象");
            HelloWorld helloWorld = (HelloWorld)applicationContext.getBean("a1");
            //HelloWorld helloWorld = applicationContext.getBean(HelloWorld.class);
            //这种方式要求在配置文件中只配置了一个HelloWorld的bean
            helloWorld.sayHello();
        }
    }

    applicationContext.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <?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-3.0.xsd">
                                      
        <bean id="a1" class="com.test.spring01.HelloWorld">
            <property name="name2" value="spring"/>
            <!--set方法注入-->
        </bean>
    </beans>

    运行结果

    调用构造函数...

    创建对象

    Hello,spring


    也可以通过构造方法注入

    1
    2
    3
    4
    5
    6
    <!--通过构造方法来配置bean属性-->
    <bean id="car" class="com.atguigu.spring.beans.Car"><!--参数和构造函数的参数对应-->
        <constructor-arg value="Audi" index="0"></constructor-arg>
        <constructor-arg value="Shanghai" index="1"></constructor-arg>
        <constructor-arg value="300000" type="double"></constructor-arg>
    </bean>
    1
    2
    3
    4
    5
    6
    <!--使用构造器注入属性值可以指定参数的位置和参数的类型,以区分重载的构造器-->
    <bean id="car2" class="com.atguigu.spring.beans.Car">
        <constructor-arg value="Baoma" type="java.lang.String"></constructor-arg>
        <constructor-arg value="Shanghai" type="java.lang.String"></constructor-arg>
        <constructor-arg value="400000" type="int"></constructor-arg>
    </bean>

    特殊标记时也可以下面这么写

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <bean id="car2" class="com.atguigu.spring.beans.Car">
        <constructor-arg value="Baoma" type="java.lang.String"></constructor-arg>
        <constructor-arg type="java.lang.String">
            <value><![CDATA[<Shanghai^>]]></value>
        </constructor-arg>
        <constructor-arg type="int">
            <value>400000</value>
        </constructor-arg>
    </bean>

    引用类型

    1
    2
    3
    4
    5
    <bean id="person" class="com.atguigu.spring.beans.Person">
        <property name="name" value="Tom"></property>
        <property name="age" value="34"></property>
        <property name="car" ref="car2"></property><!--引用car2-->
    </bean>

    内部bean,不能被外部引用,只能在内部使用

    1
    2
    3
    4
    5
    6
    7
    8
    <!--内部bean-->
    <property name="car"><!--上面的car可以这么写-->
        <bean class="com.atguigu.spring.beans.Car">
            <constructor-arg value="Ford"></constructor-arg>
            <constructor-arg value="Changan"></constructor-arg>
            <constructor-arg value="200000" type="double"></constructor-arg>
        </bean>
    </property>

    赋null值

    1
    2
    <!--测试值赋null-->
    <constructor-arg><null/></constructor-arg>

    为级联属性赋值(必须有set方法) 要先创建car才能赋值

    1
    2
    3
    <constructor-arg ref="car"></constructor-arg>
    <!--为级联属性赋值-->
    <property name="car.macSpeed" value="240"></property>

    为集合属性赋值(list set map)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <bean id="person3" class="com.atguigu.spring.collections.Person">
        <property name="name" value="Tom"></property>
        <property name="age" value="34"></property>
        <property name="cars"><!--cars是Person类的一个list类型的属性-->
            <list>
                <ref bean="car">
                <ref bean="car2">
            </list>
        </property>
    </bean>
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <!--配置Map属性值-->
    <bean id="person4" class="com.atguigu.spring.collections.Person">
        <property name="name" value="Tom"></property>
        <property name="age" value="34"></property>
        <property name="cars"><!--cars是Person类的一个map类型的属性-->
            <map>
                <entry key="AA" value-ref="car"></entry>
                <entry key="BB" value-ref="car2"></entry>
            </map>
        </property>
    </bean>
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <!--配置Peoperties属性值-->
    <bean id="dataSource" class="com.atguigu.spring.collections.dataSource">
        <property name="peoperties">
            <props>
                <prop key="user">root</prop>
                <prop key="password">123456</prop>
                <prop key="jdbcUrl">jdbc:mysql:///test</prop>
                <prop key="driverClass">com.mysql.jdbc.Driver</prop>
            </props>
        </property>
    </bean>
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <!--配置单例的集合bean,以供多个bean进行引用,需要导入util命名空间-->
    <util:list id="cars">
        <ref bean="car">
        <ref bean="car2">
    </util:list>
    <bean id="person4" class="com.atguigu.spring.collections.Person">
        <property name="name" value="Jack"></property>
        <property name="age" value="29"></property>
        <property name="cars" ref="cars"></property><!--引用上面配置的cars-->
    </bean>
    1
    2
    3
    <!--通过P命名空间为bean的属性赋值,需要先导入P命名空间-->
    <bean id="person5" class="com.atguigu.spring.collections.Person" p:age="35" p:name="Shang" p:cars-ref="cars">
    </bean>

    自动装配(Person类中有address属性和car属性)

    byName根据bean的名字和当前bean的setter风格的属性名进行自动装配。

    byType根据bean的类型和当前bean的数学的类型进行自动装配。(如果有两个类型一样的bean就会出错)

    缺点:在bean配置文件里设置autowire属性进行自动装配将会装配bean的所有属性。若只希望装配个别属性时,autowire属性就不够灵活了。autowire属性要么根据类型自动装配,要么根据名称自动装配,不能两者兼而有之。

    一般情况下,在是寄到 项目中很少使用自动装配功能,因为和自动装配功能所带来的好处比起来,明确清晰的配置文档更有说服力一些。

    1
    2
    3
    4
    5
    <bean id="address" class="com.atguigu.spring.beans.autowire.Address" p:city="Beijing" p:street="Huilongguan"></bean>
     
    <bean id="car" class="com.atguigu.spring.beans.autowire.Car" p:brand="Audi" p:price="30000"></bean>
     
    <bean id="person" class="com.atguigu.spring.beans.autowire.Person" p:name="Tom" p:autowire="byName"></bean>

    bean配置的继承

    1
    2
    3
    4
    <bean id="address" class="com.atguigu.spring.beans.autowire.Address" p:city="Beijing" p:street="Wudaokou">
    </bean>
    <!--bean配置的继承:使用bean的parent属性指定继承哪个bean的配置-->
    <bean id="address2" p:street="Dazhongsi" parent="address"></bean>

    抽象bean,只能被继承

    1
    2
    3
    4
    <!--抽象bean:bean的abstract属性为true的bean,不能被IOC容器实例化
    若一个bean的class属性没有指定,则该bean必须是一个抽象的bean。类似抽象类
    -->
    <bean id="address" p:city="Beijing" p:street="Wudaokou" abstract="true"></bean>

    bean之间的依赖关系

    Spring允许用户通过depends-on属性设定Bean前置依赖的Bean,前置依赖的Bean会在本Bean实例化之前创建好。如果前置依赖于多个Bean,则可以通过逗号、空格的方式配置多个Bean。

    1
    2
    3
    <bean id="car" class="com.atguigu.spring.autowire.Car" p:brand="Audi" p:price="30000"></bean>
    <!--要求在配置person时,必须有一个关联的car。person这个bean依赖于car这个bean-->
    <bean id="person" class="som.atguigu.spring.beans.autowire.Person" p:name="Tom" p:address-ref="address2" depends-on="car"></bean>

    bean配置的作用域

    默认为单例singleton,容器初始化时创建bean实例,在整个容器的生命周期里只创建一个bean。

    prototype原型,容器初始化时不创建bean实例,在每次请求时创建一个新的bean实例并返回。

    1
    2
    3
    4
    <bean id="car" class="com.atguigu.spring.autowire.Car" scope="prototype">
        <property name="brand" value="Audi"></property>
        <property name="price" value="300000"></property>
    </bean>

    引入外部配置文件

    不引入配置文件时这么写.  beans-properties.xml

    1
    2
    3
    4
    5
    6
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="root"></property>
        <property name="password" value="123456"></property>
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql:///test"></property>
    </bean>
    1
    2
    3
    ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-properties.xml");
    DataSource dataSource = (DataSource)ctx.getBean("dataSource");
    System.out.println(dataSource.getConnection());//建立连接

    引入外部配置文件

    db.properties

    1
    2
    3
    4
    user=root
    password=123456
    driverClass=com.mysql.jdbc.Driver
    jdbcUrl=jdbc:mysql:///test

    beans-properties.xml写法

    1
    2
    3
    4
    5
    6
    7
    8
    <!--导入属性文件--><!--要导入context命名空间-->
    <context:property-placeholder location="classpath:db.properties"/>
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="${user}"></property>
        <property name="password" value="${password}"></property>
        <property name="driverClass" value="${driverClass}"></property>
        <property name="jdbcUrl" value="${jdbcUrl}"></property>
    </bean>

    Spring表达式语言:SpEL。支持运行时查询和操作对象。

    字面量的表示

    整数 

    1
    <property name="count" value="#{5}"/>

    小数 

    1
    <property name="frequency" value="#{89.7}"/>

    科学计数法 

    1
    <property name="capacity" value="1e4"/>

    String可以使用单引号或者双引号作为字符串的定界符号

    1
    2
    <property name="name" value="#{'chuck'}"/>
    <property name="name" value='#{"chuck"}'/>

    Boolean 

    1
    <property name="enabled" value="#{false}"/>

    引用其他对象,等同ref

    1
    2
    <!--通过value属性和SpEL配置bean之间的引用关系-->
    <property name="prefix" value="#{prefixGernerator}"/>

    引用其他对象的属性

    1
    <property name="suffix" value="#{prefixGernerator.suffix}"/>

    调用其他方法,还可以链式操作

    1
    <property name="suffix" value="#{prefixGernerator.toString()}"/>
    1
    2
    <!---方法的连缀-->
    <property name="suffix" value="#{prefixGernerator.toString().toUpperCase()}"/>
    1
    <property name="price" value="#{T(java.jang.Math).PI*80}"></property>
    1
    2
    3
    4
    5
    6
    <!--使用SpEL表达式来引用其他的bean-->
    <property name="car" value="#{car}"></property>
    <!--使用SpEL表达式来引用其他的bean的属性-->
    <property name="city" value="#{address.city}"></property>
    <!--在SpEL中使用运算符-->
    <property name="info" value="#{car.price>300000?'金玲':'白领'}"></property>

    为bean指定init方法和destroy方法

    1
    2
    3
    4
    5
    <bean id="car" class="com.atguigu.spring.bean.Car"
    init-method="init" destroy-method="destroy"><!--init和destroy对应Car类中的init destroy方法-->
        <property name="brand" value="Audi"></property>
    </bean>
    <!--setBrand之后调用init方法,ctx.close();时调用destroy方法-->

    Bean后置处理器允许在调用初始化方法前后对bean进行额外的处理。Bean后置处理器对IOC容器里的所有的Bean实例逐一处理,而非单一实例。其典型应用是:检查Bean属性的正确性或根据特定的标准更改Bean属性。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    public class MyBeanPostProcessor implements BeanPostProcessor{
        //处理所有bean
        @override
        public Object postProcessBeforeInitialization(Object bean, Stirng beanName)throws BeansException{
        //可以在这里进行一些操作
        if("car".equals(beanName)){
        //...
        }
            System.out.println("postProcessBeforeInitialization...");
            return bean;
        }
         
         
        @override
        public Object postProcessAfterInitialization(Object bean, Stirng beanName)throws BeansException{
            System.out.println("postProcessAfterInitialization...");
            //可以在这里对bean的属性进行更改...安全隐患
            return bean;
        }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <!--配置文件中配置bean的后置处理器。不需要配置id,IOC容器自动识别是一个BeanPostProcessor-->
    <!--
    实现BeanPostProcessor接口,并且提供实现
    Object postProcessBeforeInitialization(Object bean, Stirng beanName)  init-method之前调用
    Object postProcessAfterInitialization(Object bean, Stirng beanName)  init-method之后调用
    bean: bean实例本身
    beanName:IOC容器配置的bwan的名字
    返回值:实际上返回给用户的bean。可以在以上两个方法中修改返回的bean,甚至返回一个新的bean
    -->
    <bean class="com.atguigu.spring.MyBeanPostProcessor"></bean>

    Spring IOC容器对Bean的生命周期进行管理的过程

    -通过构造器或工厂方法创建Bean实例

    -为bean的属性设置值和对其他bean的引用

    -将bean实例传递给bean后置处理器的postProcessBeforeInitialization方法

    -调用bean的初始化方法

    -将bean实例传递给bean后置处理器的postProcessAfterInitialization方法

    -bean可以使用了

    -容器关闭时,调用bean的销毁方法


    静态工厂方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    /**
    *静态工厂方法:直接调用某一个类的静态方法就可以返回bean的实例
    */
    public class StaticCarFactory{
        private static Map<String, car> cars = new HashMap<String, Car>();
        static{
            cars.put("audi"new Car("audi"300000));
            cars.put("ford"new Car("ford"400000));
        }
        //静态工厂方法
        public static Car getCar(String name){
            return cars.get(name);
        }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <!--通过静态工厂方法来配置bean-->
    <!--
        class属性:指向静态工程方法的全类名
        factory-method:静态工厂方法的名字
        constructor-arg:如果工厂方法需要传入参数,使用constructor-arg来配置参数
    -->
    <bean id="car1"
        class="com.atguigu.spring.StaticCarFactory"
        factory-method="getCar">
        <constructor-arg value="audi"></constructor-arg>
    </bean>
    1
    Car car = (Car)ctx.getBean("car1");//取对象

    实例工厂方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    /**
    *实例工厂方法,即先需要创建工厂,然后调用工厂的实例方法来返回bean的实例
    */
    public class InstanceCarFactory{
        private Map<String, car> cars = null;
        public InstanceCarFactory(){
        cars = new HashMap<String, Car>();
            cars.put("audi"new Car("audi"300000));
            cars.put("ford"new Car("ford"400000));
        }
         
        public Car getCar(String name){
            return cars.get(name);
        }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <bean id="carFactory" class="com.atguigu.spring.InstanceCarFactory"></bean>
    <!--通过实例工厂方法来配置bean-->
    <!--
        factory-bean属性:指向实例工程方法的全类名
        factory-method:方法的名字
        constructor-arg:如果工厂方法需要传入参数,使用constructor-arg来配置参数
    -->
    <bean id="car2" factory-bean="carFactory" factory-method="getCar">
        <constructor-arg value="audi"></constructor-arg>
    </bean>
    1
    Car car = (Car)ctx.getBean("car2");//取对象

    通过FactoryBean配置Bean

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    public class CarFactoryBean implements FactoryBean{
        private String name;
     
        public String getName() {
            return name;
        }
     
        public void setName(String name) {
            this.name = name;
        }
             
            @Override
        public Object getObject() throws Exception {
            return new Car(name, "beijing");//调用构造函数
        }
             
            @Override
        public Class getObjectType() {
            return Car.class;
        }
     
        @Override
        public boolean isSingleton() {
            return true;
        }
     
    }
    1
    2
    3
    <bean id="car" class="com.test.spring04.CarFactoryBean">
        <property name="name" value="BMW"></property>
    </bean>
    1
    2
    Car car = (Car) applicationContext.getBean("car");
    System.out.println(car);

    在IOC容器中通过注解配置Bean

    组件扫描(component scanning):Spring可以从classpath下自动扫描、侦测和实例化具有特定注解的组件。

    特定组件包括:

    -@Component 基本注解,标识了一个受Spring管理的组件

    -@Repository 标识持久层组件

    -@Service 标识服务层(业务层)组件

    -@Controller 标识表现层组件

    对于扫描到的组件,Spring有默认的莫名策略:使用非限定类名,第一个字母小写,也可以在注解中通过value属性值标识组件的名称。

  • 相关阅读:
    忙碌的一月
    SharePoint Portal Server 2003书籍计划最新进展
    如何判断Assembly是Debug还是Release?
    C#和C++的一个有意思的差别
    Enterprise Development Reference Architecture(ShadowFax)
    一个“轻量级”的SharePoint文档流转WebPart
    11月25日下午14:00,CSDN在线SharePoint TechTalk
    到北京后的第一篇随笔
    SOA & Messaging Patterns
    操作SharePoint Object Model完成两项操作的文档
  • 原文地址:https://www.cnblogs.com/yudar/p/4603127.html
Copyright © 2011-2022 走看看