Spring IoC/DI和注解注入bean生命周期

一、简介

      Spring 的核心是控制反转(IoC)和面向切面(AOP)。

      Spring 官网:https://spring.io/projects/spring-framework

1、IoC:Inversion of Control(控制反转)

    控制反转是一个通用的概念,不是什么新技术而是一种设计思想,好比于MVC。

    其本意就是将原本程序中手动创建对象的控制权,交由 Spring框架来原理。

    其作用是创建对象并且维护对象之间的依赖关系,实现了程序的解耦合。

2、DI:Dependency Injection(依赖注入)

    依赖注入是指 Spring创建对象的过程中,将对象依赖的属性(常量,对象,集合)通过配置设值给该对象。

    Spring支持的依赖注入方式:xml配置注入( setter方法注入,构造方法注入等)和注解注入

3、Spring IoC容器(其原理:反射和内省机制

      BeanFactory:生产 bean对象的工厂,Spring最底层的接口,只提供了IoC容器的功能:负责配置,创建和管理bean,被 Spring IoC容器管理的对象称为bean。Spring IoC容器通过读取配置文件中的配置元数据,通过元数据对应用中的各个对象进行实例化和装配。在应用中,一般不使用BeanFactory,而推荐使用 ApplicationContext(应用上下文)

     ApplicationContext 接口继承了BeanFactory接口,还提供了AOP集成、国际化处理等功能

4、BeanFactory与ApplicationContext创建bean的区别

     BeanFactory:需要等到获取某个bean的时候才会才会创建该bean,即延迟初始化

     ApplicationContext:在启动Spring容器时就会创建所有的bean(Web应用中推荐)

    在xml中也可以配置延迟 lazy-init

 

二、xml配置注入bean

1. setter方法注入

     指 IoC容器通过成员变量的 setter 方法来注入被依赖对象,使用 property标签。这种注入方式简单、直观,因而在 Spring 依赖注入里大量使用。

mvc 类

public class User {
	private int id;
	private String username;
	private String password;
	private Map map = new HashMap();
	private List list = new ArrayList<>(); 	// Set 类同 List

    ... 必须提供 setter 方法
}


public class UserServiceImpl implements UserService{
	//面向接口编程
	private UserDao userDao;

	public void setUserDao(UserDao userDao) {
		this.userDao = userDao;
	}

    ... 必须提供 setter 方法
}

配置文件:




	
		
		
                
			123<]]>
		
		
			
				
				
			
		
		
			
				lisi
				zs
			
		
	
	

	
		
	

测试类:

	@Test
	public void test() {
		// 1.初始化ioc容器(装对象的容器)
		ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
	
		//2.从容器中获得创建好的对象
		User user = context.getBean("user", User.class);
		System.out.println(user);
	}

-------
User [id=5, username=admin, password=>123<, map={java=80, spring=85}, list=[lisi, zs]]

2. 构造方法注入:

    指利用构造器来设置依赖关系的方式,使用 constructor-arg标签。通俗来说,就是驱动Spring在底层以反射方式执行带指定参数的构造器,当执行带参数的构造器时,就可利用构造器参数对成员变量执行初始化——这就是构造注入的本质。

mvc 类:

public class UserServiceImpl implements UserService{
	//面向接口编程
	private UserDao userDao;
	private User user;
	private int num;
	private String str;

	public UserServiceImpl(UserDao userDao, User user, int num, String str) {
		super();
		this.userDao = userDao;
		this.user = user;
		this.num = num;
		this.str = str;
	}
}

配置文件:




	
		
		
	
	

	
		
		
		
		
	

name - 参数的名字   或者   index - 参数的索引位置 从0开始(注意:构造方法的参数顺序)

ref - 指引用类型,指向另外一个bean标签的id  

vlaue -  指简单类型的值

测试类:

	@Test
	public void test() {
		// 1.初始化ioc容器(装对象的容器)
		ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
	
		//2.从容器中获得创建好的对象
		UserServiceImpl userService = context.getBean("userService",UserServiceImpl.class);
		System.out.println(userService);
	}
-------	
UserServiceImpl [userDao=cn.jq.springdemo.dao.UserDaoImpl@543c6f6d, user=User [id=5, username=admin, password=null, map={}, list=[]], num=20, str=adminstr]

上面两种注入方式的对比

1)setter方法注入优点:

  • 与传统的JavaBean的写法更相似,程序开发人员更容易理解、接受。通过setter方法设定依赖关系显得更加直观、自然。
  • 对于复杂的依赖关系,如果采用构造注入,会导致构造器过于臃肿,难以阅读。Spring在创建Bean实例时,需要同时实例化其依赖的全部实例,因而导致性能下降。而使用设值注入,则能避免这些问题。
  • 尤其在某些成员变量可选的情况下,多参数的构造器更加笨重。

2)构造注入优点:

  • 构造注入可以在构造器中决定依赖关系的注入顺序,优先依赖的优先注入。
  • 对于依赖关系无需变化的Bean,构造注入更有用处。因为没有setter方法,所有的依赖关系全部在构造器内设定,无须担心后续的代码对依赖关系产生破坏。
  • 依赖关系只能在构造器中设定,则只有组件的创建者才能改变组件的依赖关系,对组件的调用者而言,组件内部的依赖关系完全透明,更符合高内聚的原则。

注意:
      建议采用settter注入为主,构造注入为辅的注入策略。对于依赖关系无须变化的注入,尽量采用构造注入;而其他依赖关系的注入,则考虑采用设值注入。

 

3、Spring的自动装配(了解)

    Spring自动装配可通过 元素的 default-autowire属性指定,该属性对配置文件中所有的Bean起作用;

     也可通过对 元素的 autowire属性指定,该属性只对该Bean起作用。

模式 描述
no 这是默认的设置,它意味着没有自动装配,你应该使用显式的bean引用来连线。你不用为了连线做特殊的事。在依赖注入章节你已经看到这个了。
byName 属性名自动装配。Spring 容器看到在 XML 配置文件中 bean 的自动装配的属性设置为 byName。然后尝试匹配,并且将它的属性与在配置文件中被定义为相同名称的 beans 的属性进行连接。
byType 属性数据类型自动装配。Spring 容器看到在 XML 配置文件中 bean 的自动装配的属性设置为 byType。然后如果它的类型匹配配置文件中的一个确切的 bean 名称,它将尝试匹配和连接属性的类型。如果存在不止一个这样的 bean,则一个致命的异常将会被抛出。
constructor 类似于 byType,但该类型适用于构造函数参数类型。如果在容器中没有一个构造函数参数类型的 bean,则一个致命错误将会发生。
autodetect Spring首先尝试通过 constructor 使用自动装配来连接,如果它不执行,Spring 尝试通过 byType 来自动装配。

常用两种模式:

      byTpye模式:Spring容器会基于反射查看bean定义的类,然后找到与依赖类型相同的bean注入到另外的bean中,这个过程需要借助setter注入来完成,因此必须存在set方法,否则注入失败。

      byName模式:此时Spring只会尝试将属性名与bean名称进行匹配,如果找到则注入依赖bean。

mvc 类

public class UserServiceImpl implements UserService{
	private UserDao userDao; //面向接口编程
	private User user;

    ... 必须提供 setter 方法
}

配置文件:




	
		
		
		
			123<]]>
		
	
	

	
	
	

测试类:

	@Test
	public void test() {
		// 1.初始化ioc容器(装对象的容器)
		ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
	
		//2.从容器中获得创建好的对象
		UserServiceImpl userService = context.getBean("userService",UserServiceImpl.class);
		System.out.println(userService);
	}
------
UserServiceImpl [userDao=cn.jq.springdemo.dao.UserDaoImpl@13c27452, user=User [id=5, username=admin, password=>123<, map={}, list=[]]]

    如果Spring容器中没有找到可以注入的实例bean时,将不会向依赖属性值注入任何bean,这时依赖bean的属性为 null 或 基本类型默认值。

 

三、注解注入bean

       Spring 使用注解,通过"@XXX"的方式,让注解与Java Bean紧密结合,既大大减少了配置文件的体积,又增加了Java Bean的可读性与内聚性。注意:

      首先,在 applicationContext.xml核心配置文件中需要用到 context 命名空间,然后使用 标签告诉spring框架,配置了注解的类的位置。     

    base-package属性:指定spring扫描注解的类所在的包(包含子包)。当需要扫描多个包的时候,可以使用逗号分隔。

	
	

    

1. 注解说明:

       Component 最初spring框架设计的,后来为了标识不同代码层,衍生出Controller,Service,Repository三个注解 作用相当于配置文件的bean标签,被注解的类,spring始化时,就会创建该对象。它们的功能都是相同的,只是用于标注不同类型的组件

只能添加在类上  不能添加在抽象类和接口上:

      @Controller       用于标注控制层组件,即web业务层。

      @Service          用于标注业务层组件,即service层。

      @Repository(value="userDao")     用于标注数据访问组件,即dao层。

      @Component    泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。

      @Scope(scopeName="singleton")    用于指定scope作用域的(控制类生成的时候采用单例还是多例)

注解属性 value 对应的是创建的对象的名字 和id相同 (缺省配置下默认的名字为 类名首字母小写)

定义在类的 属性字段上:

      @Value(value="112")      给简单类型属性赋值,可以用在方法上或属性上

      @Resource(name="user")对象引用类型赋值,该值user类必须已经声明(在配置文件中已配置或在类中已经注解)

说一下@Resource 的装配顺序:
(1)、@Resource后面没有任何内容,默认通过name属性去匹配bean,找不到再按type去匹配
(2)、指定了name或者type则根据指定的类型去匹配bean
(3)、指定了name和type则根据指定的name和type去匹配bean,任何一个不匹配都将报错

 

    @Autowired 自动装配,给对象引用类型赋值,其作用是为了消除代码Java代码里面的getter/setter与bean属性中的property。

    @Autowired(required=false) :Spring容器找不到属性就抛出异常,若设置required=false即不再抛出异常而认为属性为null

实现类要是有多个,此时可以使用@Qualifier注解来指定你要注入Bean的名称

    @Autowired
    @Qualifier("student2")

2. @Autowired和@Resource两个注解的区别:
    1)、@Autowired 默认按照byType方式进行bean匹配,@Resource默认按照byName方式进行bean匹配
    2)、@Autowired 是Spring的注解,@Resource是J2EE的注解,

3. Spring常用注解汇总

@Configuration把一个类作为一个IoC容器,它的某个方法头上如果注册了@Bean,就会作为这个Spring容器中的Bean。
@Scope注解 作用域
@Lazy(true) 表示延迟初始化
@Service用于标注业务层组件、 
@Controller用于标注控制层组件(如struts中的action)
@Repository用于标注数据访问组件,即DAO组件。
@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
@Scope用于指定scope作用域的(用在类上

@PostConstruct用于指定初始化方法(用在方法上)
@PreDestory用于指定销毁方法(用在方法上)
@DependsOn:定义Bean初始化及销毁时的顺序
@Primary:自动装配时当出现多个Bean候选者时,被注解为@Primary的Bean将作为首选者,否则将抛出异常
@Autowired 默认按类型装配,如果我们想使用按名称装配,可以结合@Qualifier注解一起使用。如下:
@Autowired @Qualifier("personDaoBean") 存在多个实例配合使用
@Resource默认按名称装配,当找不到与名称匹配的bean才会按类型装配。

@PostConstruct 初始化注解
@PreDestroy 摧毁注解 默认 单例  启动就加载
@Async异步方法调用

 

注释参考文章:  Spring注解大全

 

四、泛型依赖注入(spring 4.x以上版本才有

       泛型依赖注入就是允许我们在使用spring进行依赖注入的同时,利用泛型的优点对代码进行精简,将可重复使用的代码全部放到一个类之中,方便以后的维护和修改。同时在不增加代码的情况下增加代码的复用性。

       BaseDao 类: 泛型方法参数控制

       BaseService   类: 对象引用属性 baseDao控制,泛型注入 

 

五、转载 Spring中bean的作用域与生命周期

      Spring中的 bean默认都是单例的,详情参考转载的这篇文章,图来自网络

    Spring IoC/DI和注解注入bean生命周期_第1张图片

 

ends~ 

你可能感兴趣的:(Spring)