zoukankan      html  css  js  c++  java
  • 二、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>

        

  • 相关阅读:
    巴洛克式和哥特式的区别
    推荐阅读书籍,是时候再行动起来了。
    AtCoder ABC 159F Knapsack for All Segments
    AtCoder ABC 159E Dividing Chocolate
    AtCoder ABC 158F Removing Robots
    AtCoder ABC 158E Divisible Substring
    AtCoder ABC 157F Yakiniku Optimization Problem
    AtCoder ABC 157E Simple String Queries
    AtCoder ABC 157D Friend Suggestions
    AtCoder ABC 156F Modularness
  • 原文地址:https://www.cnblogs.com/qf123/p/10240216.html
Copyright © 2011-2022 走看看