Spring入门(2)—— IoC与DI使用、纯注解配置

IoC基于XML的使用

一、创建工程

环境

maven3.6

jdk1.8

spring5.0.7

ide的话随便,创建maven项目即可

工程搭建

1.pom.xml


    4.0.0
    com.example
    spring-demo1
    0.0.1-SNAPSHOT

    
        
        
            org.springframework
            spring-beans
            5.0.7.RELEASE
        
        
            org.springframework
            spring-core
            5.0.7.RELEASE
        
        
            org.springframework
            spring-context
            5.0.7.RELEASE
        
        
            org.springframework
            spring-expression
            5.0.7.RELEASE
        

        
        
            junit
            junit
            4.12
        

    
    
        
            
            
                org.apache.maven.plugins
                maven-compiler-plugin
                3.2
                
                    1.8
                    1.8
                    UTF-8
                
            
        
    

2. 创建spring配置文件(resources路径下) -- applicationContext.xml






二、实现

演示

1. 思路

编写UserService接口的实现类

将UserService实现类交给Spring IoC容器管理

从Spring IoC容器中获取UserService实现类

2. UserService

public interface UserService {

	void saveUser();
}

3. UserServiceImpl

public class UserServiceImpl implements UserService {
	@Override
	public void saveUser() {
		System.out.println("IoC 演示 之UserService");
	}

}

4. applicationContext.xml




    
    

5. 测试类TestSpringIoC.java

public class TestSpringIoC {
	@Test
	public void test1() {
		// 创建ApplicationContext容器
		ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
		// 方式1:根据Bean的类型,从容器中获取实例
		UserService service1 = context.getBean(UserService.class);
		// 方式2:根据bean的id从容器中获取bean的实例
		UserService service2 = (UserService) context.getBean("userService");
		
		service1.saveUser();
		service2.saveUser();
	}
}

bean标签详解

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

实例化bean的三种方式

1. 使用默认无参构造函数(重点)

在默认情况下:它会根据默认无参构造函数来创建类对象。
如果 bean 中没有默认无参构造函数,将会创建失败。

2. 静态工厂(了解)

/**
* 模拟一个静态工厂,创建业务层实现类
*/
public class StaticFactory {
    public static UserService createUserService(){
        return new UserServiceImpl();
    }
}

3. 实例工厂(了解)

/**
* 模拟一个实例工厂,创建业务层实现类
* 此工厂创建对象,必须现有工厂实例对象,再调用方法
*/
public class InstanceFactory {
    public UserService createUserService(){
        return new UserServiceImpl();
    }
}




DI(依赖注入)介绍

一、介绍

什么是依赖?
    依赖指的就是Bean实例中的属性
    属性分为:简单类型(8种基本类型和String类型)的属性、POJO类型的属性、集合数组类型的属性。
什么是依赖注入?
    依赖注入:Dependency Injection。它是 spring 框架核心 ioc 的具体实现
为什么要进行依赖注入?
    我们的程序在编写时,通过控制反转,把对象的创建交给了 spring,但是代码中不可能出现没有依赖的情况。
    ioc 解耦只是降低他们的依赖关系,但不会消除。例如:我们的业务层仍会调用持久层的方法。那这种业务层和持久层的依赖关系,在使用 spring 之后,就让 spring 来维护了。
    简单的说,就是坐等框架把持久层对象传入业务层,而不用我们自己去获取。
 

二、依赖注入的方式(基于XML)

1. 构造函数注入

顾名思义,就是使用类中的构造函数,给成员变量赋值。
注意,赋值的操作不是我们自己做的,而是通过配置的方式,让 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实现");
	}
}

使用构造函数的方式,给 service 中的属性传值要求:类中需要提供一个对应参数列表的构造函数。
    涉及的标签:constructor-arg

  • index:指定参数在构造函数参数列表的索引位置
  • name:指定参数在构造函数中的名称
  • value:它能赋的值是基本数据类型和 String 类型
  • ref:它能赋的值是其他 bean 类型,也就是说,必须得是在配置文件中配置过的 bean

    
    

2. set方法注入(重点)

set方法注入又分为手动装配方式注入和自动装配方式注入。

  • 手动装配方式(XML方式):bean标签的子标签property,需要在类中指定set方法。
  • 自动装配方式(注解方式,后面讲解):@Autowired注解、@Resource注解。

@Autowired:一部分功能是查找实例,从spring容器中根据类型(java类)获取对应的实例。另一部分功能就是赋值,将找到的实例,装配给另一个实例的属性值。(注意事项:一个java类型在同一个spring容器中,只能有一个实例)

@Resource:一部分功能是查找实例,从spring容器中根据Bean的名称(bean标签的名称)获取对应的实例。另一部分功能就是赋值,将找到的实例,装配给另一个实例的属性值。
 

3. 使用p名称空间注入数据(本质上还是调用set方法,自行了解)

1. 步骤一:需要先引入 p 名称空间
    * 在schema的名称空间中加入该行:xmlns:p="http://www.springframework.org/schema/p"

2. 步骤二:使用p名称空间的语法
    * p:属性名 = ""
    * p:属性名-ref = ""

3. 步骤三:测试

三、依赖注入不同类型的属性(基于XML)

简单类型(value)


    
    

引用类型(ref)

ref就是reference的缩写,是引用的意思。


    


集合类型(数组)

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



    
        
            //如果集合内是简单类型,使用value子标签,如果是POJO类型,则使用bean标签
            美美
            小风
            
        
    

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


    
        
        哈哈
        呵呵
    

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


    
        
        
        
    

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


    
        root
        123
    

IoC和DI基于注解使用

学习基于注解的 IoC 配置,大家脑海里首先得有一个认知,即注解配置和 xml 配置要实现的功能都是一样的,都是要降低程序间的耦合。只是配置的形式不一样。
关于实际的开发中到底使用xml 还是注解,每家公司有着不同的使用习惯。所以这两种配置方式我们都需要掌握。
我们在讲解注解配置时,采用上一节的案例,把 spring 的 xml 配置内容改为使用注解逐步实现。

一、Ioc注解的使用

spring配置文件中,配置context:component-scan标签

Spring入门(2)—— IoC与DI使用、纯注解配置_第1张图片

类上面加上注解@Component,或者它的衍生注解@Controller、@Service、@Repository

//在需要被spring IoC容器管理的类上面加上组件注解
//value:指定该类在容器中的唯一标识,相当于bean标签的id
//默认的bean的id就是类名首字母小写,比如这个类的bean的id是userServiceImpl
@Component(value="userService")
public class UserServiceImpl implements UserService {

二、常用注解

Ioc注解

相当于:

1. @Component注解

作用:
    把资源让 spring 来管理。相当于在 xml 中配置一个 bean。
属性:
    value:指定 bean 的 id。
    如果不指定 value 属性,默认 bean 的 id 是当前类的类名。首字母小写。

2. @Controller、@Service、@Repository注解

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

DI注解(依赖注入)

相当于:

1. @Autowired

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

2. @Qualifier

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

3. @Resource

默认按照名称(byName)进行装配,名称可以通过name属性进行指定
这个注解属于J2EE的
如果没有指定name属性,当注解写在字段上时,默认取字段名进行按照名称查找,当找不到与名称匹配的bean时才按照类型进行装配。
但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。

推荐使用@Resource注解,因为这个注解是属于J2EE的,减少了与spring的耦合。

4. @Value

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

 spring配置文件


 data.properties

id=123
//简单类型的注入(配合properties文件使用)
@Value("${id}")
private int id;

改变作用范围

1. @Scope

相当于
作用:
    指定 bean 的作用范围。
属性:
    value:指定范围的值。
    取值:singleton prototype request session globalsession

生命周期相关

相当于:
@PostConstruct和@PreDestroy

注解和XML的选择问题

注解的优势:
    配置简单,维护方便(我们找到类,就相当于找到了对应的配置)。
XML 的优势:
    修改时,不用改源码。不涉及重新编译和部署。


Spring的纯注解配置

@Configuration

  • 介绍:

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

  • 属性:

    value:用于指定配置类的字节码

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

 

@Bean

  • 介绍:

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

  • 属性:

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

  • 示例代码:
    @Configuration
    public class SpringConfiguration {
        //spring容器初始化时,会调用配置类的无参构造函数
        public SpringConfiguration(){
            System.out.println(“容器启动初始化。。。”);
        }
        @Bean
        @Scope(“prototype”)
        public UserService userService(){
            return new UserServiceImpl(1,“张三”);
        }
    }

 

@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.spring.service")
public class SpringConfiguration {

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

 

@PropertySource

  • 介绍

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

  • 属性

    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 容器中
	 */
	@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

@Import

  • 介绍

    用来组合多个配置类
    相当于spring配置文件中的import标签
    在引入其他配置类时,可以不用再写@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,后面讲解)

   

        contextClass

       

            org.springframework.web.context.

            support.AnnotationConfigWebApplicationContext

       

   

   

        contextConfigLocation

       

            com.spring.test.SpringConfiguration

       

   

   

       

            org.springframework.web.context.ContextLoaderListener

       

   


Spring 分模块开发

分模块开发的场景描述:
    表现层:spring配置文件,只想管理表现层的Bean
    业务层:spring配置文件,只想管理业务层的Bean,并且进行事务控制
    持久层:spring配置文件,只想管理持久层的Bean,并且还有需要管理数据源的Bean
为了方便管理项目中不同层的Bean对象,一般都是将一个spring配置文件,分解为多个spring配置文件。

分解之后的spring配置文件如何一起被加载呢??
    一种就是同时指定多个配置文件的地址一起加载
    另一种就是:定义一个import.xml文件,通过import标签将其他多个spring配置文件导入到该文件中,tomcat启动时只需要加载import.xml就可以。

 

你可能感兴趣的:(spring)