• 002 IOC和DI使用


    基于XML的使用

    IOC配置

    在Spring的XML文件中通过一个bean标签,完成IoC的配置
    bean标签介绍

    • bean标签作用:
      用于配置被spring容器管理的bean的信息
      默认情况下它调用的是类中的无参构造函数,如果没有无参构造函数则不能创建成功
    • bean标签属性:
      id:给对象在容器中提供一个唯一标识,用于获取对象
      class:指定类的全限定名,用于反射创建对象,默认情况下调用无参构造函数
      init-method:指定类中的初始化方法名称
      destory-method:指定类中的销毁方法名称。比如DataSource的配置中一般需要指定destory-method = “close”
      scope:指定对象的作用范围
      singleton:默认值,单例的(在整个容器中只有一个对象),生命周期如下:
      对象出生:当应用加载,创建容器时,对象就被创建了
      对象活着:只要容器在,对象一直活着
      对象死亡:当应用卸载,销毁容器时,对象就被销毁了
      prototype:多例的,每次访问对象时,都会重新创建对象实例,生命周期如下:
      对象出生:当使用对象时,创建新的对象实例
      对象活着:只要对象在使用中,就一直活着
      对象死亡:当对象长时间不用时,被java的垃圾回收器回收
      request:将Spring创建的Bean对象存入到request域中
      session:将Spring创建的Bean对象存入到session域中
      global session:WEB项目中,应用在Portlet环境。如果没有Portlet环境,那么global session相当于session

    bean实例化的三种方式
    第一种:使用默认无参构造函数
    在默认情况下:它会根据默认无参构造函数来创建对象
    如果bean中没有默认无参构造函数,将会创建失败

    <bean id="userService" class="com.UserServiceImpl"/>
    

    第二种:静态工厂(了解)
    使用StaticFactory类中的静态方法 createUserService创建对象,并存入spring容器

    /**
    * 模拟一个静态工厂,创建业务层实现类
    */
    public class StaticFactory {
    	public static UserService createUserService{
    		return new UserServiceImpl();
    	}
    
    }
    
    
    <bean id="userService" class="com.StaticFactory" factory-method="createUserService">bean>
    
    
    

    第三种:实例工厂(了解)

    /**
    *	模拟一个实例工厂,创建业务层实现类
    *	此工厂创建对象,必须现有工厂实例对象,再调用方法
    */
    public class InstanceFactory {
    	public UserService createUserService(){
    		return new UserServiceImpl();
    	}
    }
    
    
    <bean id="instancFactory" class="com.InstanceFactory">bean>
    
    <bean id="userService" factory-bean="instancFactory" factory-method="createUserService">bean>
    
    
    

    DI配置

    概述

    • 什么是依赖

    依赖指的就是Bean实例中的属性
    依赖(属性)分为:简单类型(8种基本类型和String类型)的属性、POJO类型的属性、集合数组类型的属性

    • 什么是依赖注入

    依赖注入:Dependency Injection,它是spring框架核心IoC的具体实现

    • 为什么要进行依赖注入

    我们的程序在编写时,通过控制反转,把对象的创建交给了spring,但是代码中不可能出现没有依赖的情况
    那如果一个bean中包含了一些属性,那么spring帮我们实例化了bean对象后,也需要将对应的属性信息进行赋值操作,这种属性赋值操作,就是所谓的依赖注入(获取值,注入属性)

    依赖注入的方式

    构造函数注入

    顾名思义,就是使用类中的构造函数,给成员变量赋值。注意:赋值的操作不是我们自己做的,而是通过配置的方式,让spring框架来为我们注入

    public class UserServiceImpl implements UserService {
    	private int id;
    	private String name;
    
    	public UserServiceImpl(int id, String name) {
    		this.id = id;
    		this.name = name;
    	}
    	
    	@Override
    	public void saveUser(){
    		System.out.println("保存用户:id为"+id+",name为"+name+"  Service实现")
    	}
    
    }
    
    
    
    <bean id="userService" class="com.UserServiceImpl">
    	<constructor-arg name="id" value="1">constructor-arg>
    	<constructor-arg name="name" value="zhangsan">constructor-arg>
    bean>
    
    
    
    set方法注入(重点)
    • 手动装配方式(XML方式)

    需要配置bean标签的子标签property
    需要配置bean中指定setter方法

    • 自动装配方式(注解方式)

    @Autowired:
    作用一:查找实例,从spring容器中根据Bean的类型(byType)获取实例
    作用二:赋值,将找到的实例,装配给另一个实例的属性值
    注意事项:一个java类型在同一个spring容器中,只能有一个实例
    @Resource:
    作用一:查找实例,从spring容器中根据Bean的名称(byName)获取实例
    作用二:赋值,将找到的实例,装配给另一个实例的属性值
    @Inject

    使用p名称空间注入数据

    本质上还是调用set方法
    1.步骤一:需要先引入p名称空间

    在schema的名称空间中加入该行:xmlns:p="http://www.springframework.org/schema/p"
    

    2.步骤二: 使用p名称空间的语法

    p:属性名 = ""
    p:属性名-ref = ""
    
    

    3.步骤三:测试

    <bean id="person" class="com.Person" p:pname="老王" p:car2-ref="car2"/>
    <bean id="car2" class="com.Car2">bean>
    
    依赖注入不同类型的属性

    简单类型(value)

    <bean id="userService" class="com.UserServiceImpl">
    	<property name="id" value="1">property>
    	<property name="name" value="zhangsan">property>
    bean>
    
    

    引用类型(ref)
    ref就是reference的缩写,是引用的意思

    <bean id="userService" class="com.UserServiceImpl">
    	<property name="userDao" ref="userDao">property>
    bean>
    <bean id="userDao" class="com.UserDaoImpl">bean>
    

    集合类型(数组)
    1.如果是数组或List集合,注入配置文件的方式是一样的

    <bean id="collectionBean" class="com.CollectionBean">
    	<property name="arrs">
    		<list>
    			
    			<value>aavalue>
    			<value>bbvalue>
    			<bean>bean>
    		list>
    	property>
    bean>
    

    2.如果是Set集合,注入的配置文件方式如下

    <property name="sets">
    	<set>
    	
    	set>
    property>
    

    3.如果是Map集合,注入的配置方式如下

    <property name="map">
    	<map>
    		<entry key="老王" value="38">
    		<entry key="张三" value="38">
    	map>
    property>
    
    

    4.如果是Properties集合的方式,注入的配置如下

    <property name="pro">
    	<props>
    		<prop key="name">rootprop>
    		<prop key="pass">123456prop>
    	props>
    property>
    
    
    

    基于注解和XML混合方式的使用

    IoC注解使用方法

    • 第一步:spring配置文件中,配置context:compent-scan标签
    
    <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">
        
        <context:component-scan base-package="com.service">context:component-scan>
    
    • 第二步:类上面加上注解@Component,或者它的衍生注解@Controller、@Service、@Repository
    @Service
    public class UserServiceImpl implements UserService {
    }
    

    IoC注解(创建对象)

    相当于:

    <bean id="" class="">
    

    Component注解

    • 作用:

    把资源让spring管理。相当于在xml中配置一个bean

    • 属性

    value:指定bean的id。如果不指定value属性,默认bean的id是当前类的类名,首字母小写

    Controller&Service&Repository注解
    他们三个注解都是针对@Component的衍生注解,他们的作用及属性都是一模一样的。他们只不过是提供了更加明确的语义化。
    注意:如果注解中有且只有一个属性要赋值时,且名称是value,value在赋值时可以不写。

    @Controller:一般用于表现层的注解
    @Service:一般用于业务层的注解
    @Repository:一般用于持久层的注解

    DI注解(依赖注入)

    相当于:

    <property name="" ref="">
    <property name="" value="">
    

    @Autowired

    • @Autowired默认按类型装配(byType)
    • @Autowired是由AutowiredAnnotationBeanPostProcessor类实现
    • @Autowired是spring自带的注解
    • @Autowired默认情况下要求依赖对象必须存在,如果需要允许null值,可以设置它的required属性为false,如:@Autowired(required=false)
    • 如果我们想按名称装配(byName)可以结合@Qualifier注解进行使用

    @Qualifier

    • 在自动按照类型注入的基础之上,再按照Bean的id注入
    • 它在给字段注入时不能独立使用,必须和@Autowired一起使用
    • 但是给方法参数注入时,可以独立使用

    @Resource

    • @Resource默认按名称装配(byName),可以通过@Resource的name属性指定名称,如果没有指定name属性,当注解写在字段上时,默认取字段名进行按照名称查找,当找不到与名称匹配的bean时才按照类型进行装配。
    • @Resource属于J2EE JSR250规范的实现
    • 但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配
      推荐使用@Resource注解,因为它是属于J2EE的,减少了与spring的耦合。这样代码看起来比较优雅

    @Inject

    • @Inject是根据类型进行自动装配的,如果需要按名称进行装配,则需要配合@Named
    • @Inject是JSR330中的规范,需要导入javax.inject.Inject实现注入
    • @Inject可以作用在变量、setter方法、构造函数上

    @Value

    • 给基本类型和String类型注入值
    • 可以使用占位符获取属性文件中的值
    @Value("${name}")//name是properties文件中的key
    private String name;
    

    @Autowired、@Resource、@Inject区别
    1.@Autowired是spring自带的,@Inject是JSR330规范实现的,@Resource是JSR250规范实现的,需要导入不同的包
    2.@Autowired、@Inject用法基本一样,不同的是@Autowired有一个request属性
    3.@Autowired、@Inject是默认按照类型匹配的,@Resource是按照名称匹配的
    4.@Autowired如果需要按照名称匹配需要和@Qualifier一起使用,@Inject和@Name一起使用

    改变bean作用范围的注解

    • @Scope:指定bean的作用范围,相当于下面的配置
    <bean id="" class="" scope="">
    
    • 属性

    value:指定范围的值。 取值:singleton prototype request session globalsession

    生命周期相关注解

    • @PostConstruct
    • @PreDestory
      相当于
    <bean id="" class="" init-method="" destory-method="" />
    

    关于注解和XML的选择问题

    • 注解的优势
      配置简单,维护方便(找到了类,就相当于找到了对应的配置)
    • XML的优势
      修改时,不用改源码。不涉及重新编译和部署
    • Spring管理Bean方式的比较
    基于XML配置基于注解配置
    Bean定义@Component衍生类@Repository @Service @Controller
    Bean名称通过id或name指定@Component(“person”)
    Bean注入或者通过p命名空间@Autowired按类型注入 @Qualifier按名称注入
    生命过程、Bean作用范围init-method destory-method范围scope属性@PostConstruct初始化 @PreDestory销毁 @Scope设置作用范围
    适合场景Bean来自第三方,使用其他Bean的实现类由用户自己开发

    基于纯注解方式使用

    注解和XML混合开发遗留的问题

    想想能不能将以下这些bean的配置都从xml中去掉,并且最终将XML也去掉。如果可以,就可以脱离xml配置

    • 注解扫描配置
    
    <context:component-scan base-package="com.service"/>
    <context:property-placeholder src="">context:property-placeholder>
    
    • 非自定义的Bean配置(比如:SqlSessionFactory和BasicDataSource配置)
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    	<property name="dataSource" value="dataSource">property>
    bean>
    
    • 去掉XML后,如何创建ApplicationContext
      之前创建ApplicationContext都是通过读取XML文件进行创建的

    ApplicationContext context = new ClassPathXmlApplicationContext(“beans.xml”);

    @Configuration

    相当于spring的XML配置文件
    从Spring3.0开始可以使用@Configuration定义配置类,可替换xml配置文件
    配置类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义对象,初始化Spring容器

    • 属性
      value:用于指定配置类的字节码
    • 示例代码
    @Configuration
    public class SpringConfiguration {
    	//spring容器初始化时,会调用配置类的无参构造函数
    	public SpringConfiguration(){
    		System.out.println("容器启动初始化。。。");
    	}
    }
    

    @Bean

    相当于标签
    作用为:注册bean对象,主要用来配置非自定义的bean,比如DruidDataSource、SqlSessionFactory
    @Bean标注在方法上(返回某个实例的方法)

    • 属性

    name:给当前@Bean 注解方法创建的对象指定一个名称(即bean的id)。如果不指定,默认与标注的方法名相同
    @Bean注解默认作用域为单例singleton作用域,可通过@Scope(“prototype”)设置为原型作用域

    • 示例代码
    @Configuration
    public class SpringConfiguration {
    	//spring容器初始化时,会调用配置类的无参构造函数
    	public SpringConfiguration(){
    		System.out.println("容器启动初始化。。。");
    	}
    
    	@Bean
    	@Scope("prototype")
    	public SqlSessionFactory userService(){
    		SqlSessionFactory sqlSessionFactory = new DefaultSqlSessionFactory();
    		sqlSessionFactory.setxxx();
    		return sqlSessionFactory;
    	}
    	
    }
    

    @ComponentScan

    相当于context:component-scan标签
    组件扫描器,扫描@Component、@Controller、@Service、@Repository注解的类
    该注解是编写在类上面的,一般配合@Configuration注解一起使用

    • 属性

    basePackages:用于指定要扫描的包
    value:和basePackages作用一样

    • 示例代码
      Bean类(Service类):
    @Service
    public class UserServiceImpl implements UserService {
    	@Override
    	public void saveUser() {
    		System.out.println("保存用户 Service实现");
    	}
    }
    

    配置类:

    @Configuration
    @ComponentScan(basePackages="com.service")
    public class SpringConfiguration {
    	public SpringConfiguration() {
    		System.out.println("容器初始化...");
    	}
    
    	// @Bean
    	// @Scope("prototype")
    	// public UserService userService() {
    	// 	return new UserServiceImpl(1,"张三");
    	//}
    }
    
    
    

    @PropertySource

    相当于context:property-placeholder标签
    编写在类上面,作用是加载properties配置文件

    • 属性

    value[]:用于指定properties文件路径,如果在类路径下,需要写上classpath

    • 示例代码
      配置类:
    @Configuration
    @PropertySource("classpath:jdbc.properties")
    public class JdbcConfig {
    	@Value("${jdbc.driver}")
    	private String driver;
    	@Value("${jdbc.url}")
    	private String url;
    	@Value("${jdbc.username}")
    	private String username;
    	@Value("${jdbc.password}")
    	private String password;
    
    
    
    
    	/**
    	* 创建一个数据源,并存入spring容器中
    	* @return
    	*/
    	@Bean(name = "dataSource")
    	public DataSource createDataSource() {
    		try {
    			ComboPooledDataSource ds = new ComboPooledDataSource();
    			ds.setDriverClass(driver);
    			ds.setJdbcUrl(url);
    			ds.setUser(username);
    			ds.setPassword(password);
    			return ds;
    		} catch (Exception e) {
    			throw new RuntimeException(e);
    		}
    	}
    	
    }
    
    

    properties文件

    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql:///spring
    jdbc.username=root
    jdbc.password=root

    • 问题

    当系统中有多个配置类时怎么办?想一想之前使用XML配置的时候是如何解决该问题的

    @Import

    相当于spring配置文件中的标签
    用来组合多个配置类,在引入其他配置类时,可以不用再写@Configuration注解。当然,写上也没问题

    • 属性

    value:用来指定其他配置类的字节码文件

    • 示例代码
    @Configuration
    @ComponentScan(basePackages = "com.spring")
    @Import({JdbcConfig.class})
    public class SpringConfiguration {
    }
    
    @Configuration
    @PropertySource("classpath:jdbc.properties")
    public class JdbcConfig {
    }
    

    创建纯注解方式上下文容器

    • Java应用(AnnotationConfigApplicationContext)
    ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfiguration.class);
    UserService service = context.getBean(UserService.class);
    service.saveUser();
    
    • Web应用(AnnotationConfigWebApplicationContext)
    <web-app>
    	<context-param>
    		<param-name>contextClassparam-name>
    		<param-value>
    			org.springframework.web.context.support.AnnotationConfigWebApplicationContext
    		param-value>
    	context-param>
    
    	<context-param>
    		<param-name>contextConfigLocationparam-name>
    		<param-value>
    			com.SpringConfiguration
    		param-value>
    	context-param>
    	
    	<listener>
    		<listener-class>
    			org.springframe.web.context.ContextLoaderListener
    		listener-class>
    	listener>
    web-app>
    
  • 相关阅读:
    基于Overleaf的pdf修改前后对比软件安装
    ZigBee 3.0理论教程-通用-1-02:协议架构-总
    Jmeter性能测试(压力测试)
    如何高效率学习思政知识?现在终于明白了!
    ESP8266/ESP32 通过TimeLib库获取NTP时间方法
    WPF入门教程系列二十六——DataGrid使用示例(3)
    Spring的读取和存储对象
    语音增强用到的方法总结
    uniapp离线打包apk - 安卓篇
    C语言经典例题-17
  • 原文地址:https://blog.csdn.net/m0_46695127/article/details/139720047