• 二、spring的IoC


    IoC的基本认识

    Inversion of Control:控制反转,就是将对象的创建权反转交给spring

    IoC的好处

    传统方式的程序编写,底层的实现切换了,需要修改源代码

    使用spring之后,实现类都交给IoC容器中的BeanFactory来管理,通过工厂+反射+配置文件来实现程序的解耦合

    <bean id="user" class="com.qf.demo.User">
    class BeanFactory{
    	public static Object getBean(String id) {//id:bean标签的id
    		Class clazz = Class.forName(className);//className:bean标签的class
    		return clazz.newInstance();
    	}
    }

    IoC和DI

            <bean id="user" class="com.qf.demo.User">
    		<property name="id" value="1"/>
    		<property name="name" value="qf"/>
    		<property name="age" value="18"/>
    	</bean>    

    IoC:控制反转,就是将对象的创建权反转给spring

    DI:依赖注入,前提必须有IoC的环境,然后Spring管理这个类的时候把这个类依赖的属性注入进来

    描述:  
      Class A中用到了Class B的对象b,一般情况下,需要在A的代码中显式的new一个B的对象。采用依赖注入技术之后,A的代码只需要定义一个私有的B对象,不需要直接new来获得这个对象,而是通过相关的容器控制程序来将B对象在外部new出来并注入到A类里的引用中。而具体获取的方法、对象被获取时的状态由配置文件(如XML)来指定

    Spring的工厂类

    • ApplicationContext是新版本spring的工厂类、BeanFactory是老版本spring的工厂类
    • ApplicationContext继承了BeanFactory接口
    • BeanFactory在调用getBean方法时才会生成类的实例;ApplicationContext在加载配置文件时就会生成类的实例
    • ApplicationContext接口有两个实现类
      • ClassPathXmlApplicationContext:加载类路径下的配置文件
      • FileSystemXmlApplicationContext :加载文件系统下的配置文件

    配置spring

    applicationContext.xml

    <?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="user" class="com.qf.demo.User">
    		<property name="id" value="1"/>
    		<property name="name" value="qf"/>
    		<property name="age" value="18"/>
    	</bean>
    
    </beans> 

    bean配置

    bean标签

    1. 标识
      • id:使用了唯一约束;不能使用特殊字符
      • name:未使用唯一约束;可以使用特殊字符,例如 /user
    2. 生命周期
      • init-method:bean被初始化时执行的方法
      • destroy-method:bean被销毁时执行的方法(bean必须是单例创建的才可以进行工厂关闭,多例的情况下无法工厂关闭) 
      • 测试,User类中定义两个方法init和destroy
         1 package com.qf.demo;
         2 
         3 public class User {
         4 
         5     private Long id;
         6     private String name;
         7     private Integer age;
         8     
         9     public void setId(Long id) {
        10         this.id = id;
        11     }
        12     public void setName(String name) {
        13         this.name = name;
        14     }
        15     public void setAge(Integer age) {
        16         this.age = age;
        17     }
        18     
        19     @Override
        20     public String toString() {
        21         return "User [id=" + id + ", name=" + name + ", age=" + age + "]";
        22     }
        23     
        24     public User(Long id, String name, Integer age) {
        25         super();
        26         this.id = id;
        27         this.name = name;
        28         this.age = age;
        29     }
        30     public User() {
        31         super();
        32     }
        33     
        34     public void init() {
        35         System.out.println("初始化----------");
        36     }
        37     public void destroy() {
        38         System.out.println("销毁----------");
        39     }
        40 }
        View Code

        applicationContext.xml中配置spring管理User对象时配置init属性和destroy属性

        <?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="user" class="com.qf.demo.User" init-method="init" destroy-method="destroy">
        		<property name="id" value="1"/>
        		<property name="name" value="qf"/>
        		<property name="age" value="18"/>
        	</bean>
        
        </beans>
        

        测试类

        public class TestDemo {
        
        	@Test
        	public void test() {
        //		ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //		ApplicationContext类里没有close方法
        		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        		User user1 = (User) context.getBean("user");
        		System.out.println(user1);
        //		User user2 = (User) context.getBean("user");
        //		System.out.println(user2);
        		context.close();
        	}
        }
        

        console输出结果

        初始化----------
        User [id=1, name=qf, age=18]
        销毁----------  

        注:如果bean中配置scope="prototype",测试会发现destroy不执行,即工厂无法close  

    3. 作用域
      • scope:bean的作用域属性
        • singleton:默认的,spring采用单例模式创建对象
        • prototype:spring采用多例模式创建对象 
        • request:在web项目中使用,spring创建完这个类对象后,将这个对象存入到request中
        • session:在web项目中使用,spring创建完这个类对象后,将这个对象存入到session中
        • globalSession:在web项目中使用,在porlet环境下,spring创建完这个类对象后,这个对象在其子系统中可以使用;没有porlet环境,相当于session
      • 测试1
        • 修改applicationContext.xml的bean配置,配置scope属性
          <bean id="user" class="com.qf.demo.User" scope="prototype">
        •  测试方法
          @Test
          public void test() {
          	ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
          	User user1 = (User) context.getBean("user");
          	User user2 = (User) context.getBean("user");
          	System.out.println(user2 == user1);
          }
        • console输出结果
          false  
        • 结论:采用多例模式创建对象,两次调用getBean方法创建了两个不同的对象
      • 测试2
        • 在测试1的基础上修改scope属性值为singleton
        • console输出结果
          true
        • 结论:采用单例模式创建对象,两次调用getBean方法创建了两个相同的对象

    Spring的bean管理方式

    XML方式:适用于任何场景。结构清晰,便于维护

    注解方式:如果类不是自己提供的就不能使用(没办法改源码)。开发更加简单方便

    XML方式管理Bean

    spring的bean的实例化

    1. 无参构造方式实例化bean
      • 自定义bean
        public class TestBean {
        
        	public TestBean() {
        		System.out.println("无参构造方式实例化完成");
        	}
        }
      • 配置bean 
        <bean id="test" class="com.qf.demo.TestBean"></bean>
      • 测试方法
        @Test
        public void test() {
        	ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        	TestBean test = (TestBean) context.getBean("test");
        	System.out.println(test);
        }
      • console输出
        无参构造方式实例化完成
        com.qf.demo.TestBean@635c714a
    2. 静态工厂方式实例化bean
      • 创建静态工厂类
        package com.qf.demo;
        
        public class TestBeanFactory {
        	public static Bean getBean() {
        		System.out.println("静态工厂实例化完成");
        		return new Bean();
        	}
        }
        class Bean{
        	
        }  
      • 配置bean
        <bean id="test" class="com.qf.demo.TestBeanFactory" factory-method="getBean"></bean>
    3. 实例工厂方式实例化bean
      • 创建实例工厂类
        package com.qf.demo;
        
        public class BeanInstance {
        
        	public Bean getInstance() {
        		System.out.println("实例工厂方式实例化bean完成");
        		return new Bean();
        	}
        }
      • 配置bean
        <bean id="instance" class="com.qf.demo.BeanInstance"/>
        <bean id="test" factory-bean="instance" factory-method="getInstance"/>  

    属性注入

    1. 构造方法
      • bean类中定义带参数的构造方法
        package com.qf.demo;
        
        public class User {
        	private Long id;
        	private String name;
        	private Integer age;
        	private Address address;
        	
        	public User(Long id, String name, Integer age, Address address) {
        		super();
        		this.id = id;
        		this.name = name;
        		this.age = age;
        		this.address = address;
        	}
        	public User() {
        		super();
        	}
        
        	@Override
        	public String toString() {
        		return "User [id=" + id + ", name=" + name + ", age=" + age + ", address=" + address + "]";
        	}
        }
      • 配置bean
        <bean id="address" class="com.qf.demo.Address"></bean>    
        <!-- 构造方法注入属性值,通过index索引注入 -->    
        <bean id="user" class="com.qf.demo.User">
        	<constructor-arg index="0" value="1"/>
        	<constructor-arg index="1" value="wxf"/>
        	<constructor-arg index="2" value="24"/>
        	<!-- 注入的属性值是另一个bean对象:使用ref属性设置 -->
        	<constructor-arg index="3" ref="address"/>
        </bean>
        
        <!-- 构造方法注入属性值,通过name参数名称注入 -->    
        <bean id="user1" class="com.qf.demo.User">
        	<constructor-arg name="id" value="2"/>
        	<constructor-arg name="name" value="qf"/>
        	<constructor-arg name="age" value="18"/>
        	<constructor-arg name="address" ref="address"/>
        </bean>
    2. set方法
      • bean类中定义属性的setter方法
        package com.qf.demo;
        
        public class User {
        	private Long id;
        	private String name;
        	private Integer age;
        	private Address address;
        	
        	public void setId(Long id) {
        		this.id = id;
        	}
        	public void setName(String name) {
        		this.name = name;
        	}
        	public void setAge(Integer age) {
        		this.age = age;
        	}
        	public void setAddress(Address address) {
        		this.address = address;
        	}
        	
        	@Override
        	public String toString() {
        		return "User [id=" + id + ", name=" + name + ", age=" + age + ", address=" + address + "]";
        	}
        }
      • 配置bean
        <bean id="address" class="com.qf.demo.Address"></bean>   
        <!-- set方法属性注入 -->
        <bean id="user2" class="com.qf.demo.User">
        	<property name="id" value="3"/>
        	<property name="name" value="hz"/>
        	<property name="age" value="21"/>
        	<property name="address" ref="address"/>
        </bean>
    3. p名称空间
      • 用法
        • p名称空间的引入
          • xml的beans标签中添加 xmlns:p="http://www.springframework.org/schema/p" 
        • p名称空间的使用
          • 注入普通属性:p:属性名="属性值"
          • 注入对象属性:p:属性名-ref="属性值"
      • bean类中定义属性的setter方法(类中必须有属性的setter方法,否则抛出NotWritablePropertyException提示缺少属性的setter方法)
      • 配置bean
        <?xml version="1.0" encoding="UTF-8"?>
        <beans xmlns="http://www.springframework.org/schema/beans"
        	xmlns:p="http://www.springframework.org/schema/p"
            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="address" class="com.qf.demo.Address"/>
            <bean id="user" class="com.qf.demo.User" p:id="4" p:name="wxf" p:age="18" p:address-ref="address"/>    
            
        </beans>
    4. SpEL注入
      • 基本使用
        • #{SpEL表达式}
          • 字面量表示:#{5}(整数)、#{12.6}(小数)、#{1e3}(科学记数法)、#{'admin'}(字符串)、#{false}(boolean类型)
          • 引用bean表示
            • 引用其它对象:#{address}(address对象是User类的属性)
            • 引用其它对象的属性:#{address.province}(引用address对象的province属性值)
            • 引用其它对象的方法:#{address.getProvice()}、#{address?.getProvice()}(如果address是null,就不调用getProvince()方法了)
      • bean类中定义定义属性的setter方法
      • 配置bean
        <bean id="address" class="com.qf.demo.Address" p:province="AnHui" />
        <bean id="user" class="com.qf.demo.User">
        	<property name="id" value="#{5}"/>
        	<property name="name" value="#{'qf'}"/>
        	<property name="age" value="#{21}"/>
        	<property name="address" value="#{address.getInstance()}"/>
        </bean>  

    注入集合属性

    <bean id="collectionBean" class="com.qf.demo.CollectionBean">
        	<!-- 注入数组 -->
        	<property name="arr" >
        		<list>
        			<value>wxf</value>
        			<value>admin</value>
        			<value>qf</value>
        		</list>
        	</property>
        	
        	<!-- 注入list -->
        	<property name="list" >
        		<list>
        			<value>asd</value>
        			<value>zxc</value>
        			<value>wf</value>
        		</list>
        	</property>
        	
        	<!-- 注入set -->
        	<property name="set" >
        		<set>
        			<value>1</value>
        			<value>2</value>
        			<value>3</value>
        		</set>
        	</property>
        	
        	<!-- 注入数map -->
        	<property name="map" >
        		<map>
        			<entry key="wxf" value="24"></entry>
        			<entry key="qf" value="18"></entry>
        		</map>
        	</property>
        </bean>   

    Spring的分模块开发

    • 加载配置文件时加载多个
      • ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext1.xml","applicationContext2.xml");  
    • 在配置文件中引入其它配置文件
      •  <import resource="xxx.xml"/>

    注解方式管理Bean

    IoC注解的基本使用

    1. 引入jar,使用spring注解方式管理bean,需要额外再引入aop的jar包:spring-aop-4.2.4.RELEASE.jar
      • spring-beans-4.2.4.RELEASE.jar
      • spring-context-4.2.4.RELEASE.jar
      • spring-core-4.2.4.RELEASE.jar
      • spring-expression-4.2.4.RELEASE.jar 
      • spring-aop-4.2.4.RELEASE.jar
      • com.springsource.org.apache.commons.logging-1.1.1.jar
      • com.springsource.org.apache.log4j-1.2.15.jar
    2. 引入配置文件
      1. 引入context约束
        <?xml version="1.0" encoding="UTF-8"?>
        <beans xmlns="http://www.springframework.org/schema/beans"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xmlns:context="http://www.springframework.org/schema/context" 
            xsi:schemaLocation="
                http://www.springframework.org/schema/beans 
                http://www.springframework.org/schema/beans/spring-beans.xsd
                http://www.springframework.org/schema/context 
                http://www.springframework.org/schema/context/spring-context.xsd"> 
        	
        </beans>
      2. 开启组件扫描
        <?xml version="1.0" encoding="UTF-8"?>
        <beans xmlns="http://www.springframework.org/schema/beans"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xmlns:context="http://www.springframework.org/schema/context" 
            xsi:schemaLocation="
                http://www.springframework.org/schema/beans 
                http://www.springframework.org/schema/beans/spring-beans.xsd
                http://www.springframework.org/schema/context 
                http://www.springframework.org/schema/context/spring-context.xsd"> 
        	<!-- IoC注解开发,配置组件扫描 base-package:哪些包下的类使用注解开发 -->
        	<context:component-scan base-package="com.qf.demo2"/>
        </beans>
    3. 创建spring管理的bean类
      • Address.java
        package com.qf.demo2;
        
        import org.springframework.beans.factory.annotation.Value;
        import org.springframework.stereotype.Component;
        
        @Component("address")
        public class Address {
        	@Value("安徽省")
        	private String province;
        	@Value("合肥市")
        	private String city;
        	@Override
        	public String toString() {
        		return "Address [province=" + province + ", city=" + city + "]";
        	}
        }
      • User.java
        package com.qf.demo2;
        
        import javax.annotation.Resource;
        
        import org.springframework.beans.factory.annotation.Value;
        import org.springframework.stereotype.Component;
        
        @Component("user")
        public class User {
        	@Value(value="1")
        	private Long id;
        	@Value(value="qf")
        	private String name;
        	@Value(value="18")
        	private Integer age;
        	@Resource(name="address")
        	private Address address;
        
        	@Override
        	public String toString() {
        		return "User [id=" + id + ", name=" + name + ", age=" + age + ", address=" + address + "]";
        	}
        }
    4. 测试
      • 编写测试类
        package com.qf.demo2;
        
        import org.junit.Test;
        import org.springframework.context.ApplicationContext;
        import org.springframework.context.support.ClassPathXmlApplicationContext;
        
        public class TestDemo {
        	@Test
        	public void demo() {
        		ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        		User user = (User) context.getBean("user");
        		System.out.println(user);
        	}
        }
      • 测试结果
        User [id=1, name=qf, age=18, address=Address [province=安徽省, city=合肥市]]

    IoC注解的详细使用

    1. bean上的注解
      • @Component:针对所有Spring管理的bean都可以使用
      • @Contoller:针对web层
      • @Service:针对service层
      • @Repository:针对dao层
      • 目前和使用@Component没有区别,但是推荐在web层使用@Contoller、service层使用@Service、dao层使用@Repository,结构更加清晰,而且在新版本的spring可能会扩展新的属性
    2. 注解设置属性值
      • 属性有setter方法,需要将属性注入的注解添加在setter方法上
        private String city;
        @Value("合肥市")
        public void setCity(String city) {
        	this.city = city;
        }
      • 属性没有setter方法,需要将属性注入的注解添加在属性定义上
        @Value(value="qf")
        private String name;
      • 属性上的注解
        • 普通属性
          • @Value  
        • 对象属性
          • @Autowired:设置对象类型属性的值,按照类型注入
          • @Autowired+@Qualifier("名称"):设置对象类型属性的值,按照名称注入
          • @Resource(name="名称"):设置对象类型属性的值,相当于@Autowired+@Qualifier("名称")
          • @Autowired和@Qualifier是spring框架的注解(org.springframework.beans.factory.annotation.*),@Resource不是spring的注解(javax.annotation.Resource)
    3. bean生命周期的注解
      • @PostConstruct:在bean方法上配置,相当于bean标签的init-method属性(javax.annotation.PostConstruct)
      • @PreDestroy:在bean方法上配置,相当于bean标签的destroy-method属性(javax.annotation.PreDestroy) 
    4. bean作用范围的注解
      • @Scope("可选值")
        • singleton
        • prototype
        • request
        • session
        • globalSession 

    XML和注解结合使用

    使用XML管理类,使用注解控制属性注入

    applicationContext.xml配置文件

    1. 配置组件扫描
      <!-- IoC注解开发,配置组件扫描 base-package:哪些包下的类使用注解开发 -->
      <context:component-scan base-package="com.qf.demo2"/>
      <bean id="user" class="com.qf.demo2.User"></bean>
    2. 不配置组件扫描
      <!-- 
      	激活那些已经在spring容器里注册过的bean,
      	让我们可以在没有配置扫描的情况下,使用属性注入的注解@Resource、@Autowired、@Qulifier、@Value 
      -->
      <context:annotation-config/>
      <bean id="user" class="com.qf.demo2.User"></bean>

        

  • 相关阅读:
    古代规模最大的战争:长平之战(做事不能太小气,不同的将领有不同的视角,要智胜,活着很重要)
    聚集索引更新后会不会马上重新排序
    GitHub Pages 搭建流程-基于jekyll-bootstrap
    OpenStack调研
    领域模型设计
    Load ContextCLR 探测
    Sql Server Job 简单使用
    Power Designer导出实体类和NHibernate xml文件
    解决跨域
    性能计数器
  • 原文地址:https://www.cnblogs.com/qf123/p/10240216.html
Copyright © 2020-2023  润新知