Spring依赖注入

1:为了降低Java开发的复杂性,Spring采取了4种关键策略
    通过POJO的轻量级和最小侵入性编程;
    通过依赖注入和面向接口实现松耦合;
    基于切面和惯例进行声明式编程;
    通过切面和模板减少样板式代码;
Spring竭力避免因自身的API而弄乱应用代码,不会强迫你实现Spring规范的接口或者继承Spring规范的类。相反,在基于Spring构建的应用中,他的类通常没有任何痕迹表明你使用了Spring。最坏的场景,一个类或许会使用Spring注解,但它依旧是POJO.
从这点看,配置还是注解都是各有利弊,配置虽然略显繁琐,但与代码独立。注解虽然便于快速开发,但还是具有一定耦合性。
例1:
public class Student1 implements Person{
	private Teacher teacher;

	public Student1() {
		this.teacher = new Teacher();//与Teacher紧耦合
	}
	
	public void study() {
		teacher.teach();
	}
}

例2:

public class Student implements Person{
	private Teacher teacher;

	public Student(Teacher teacher) {
		this.teacher = teacher;
	}
	
	public void study() {
		teacher.teach();
	}
}

这两个例子简略的展示了紧耦合所带来的限制,例2并没有自行的传递一个对象,而是在构造的时候将任务作为构造器参数传入,这是依赖注入的方式之一,既构造器注入
再扩展一下,假如例1中的teacher是体育老师,或者美术老师,而例2中的teacher是所有的老师,那么例1的劣势更将凸显出来,而例2却能够相应不同的teacher的操作,实现了没有与任何特定的teacher发生耦合,他并不关心是哪个具体的teacher,这就是DI【依赖注入】所带来的最大收益——松耦合。如果一个对象只通过接口【而不是具体实现或初始化过程】来表明依赖关系,那么这种依赖就能够在对象本身毫不知情的情况下,用不同的具体实现进行代替。
  但是,耦合具体两面性。一方面,紧密耦合的代码难以测试,难以复用,难以理解,并且典型的表现出“打地鼠”的bug特征,修复完一个bug,将会出现其他bug。另一方面,一定程度的耦合又是必须的,完全没有耦合的代码什么也做不了。为了完成有实际意义的功能,不同的类必须以适当的方式进行交互,总而言之,耦合是必须的,但应当被小心谨慎的使用。
         那么,怎样将特定的teacher传递给student呢,创建应用组件之间协作的行为通常称为装配。
Spring有多种装配bean的方式,采用XML是很常见的。以下为例展示:
package com.spring.dao;

public interface TeacherDao {
	
	public void teach();
}

Teacher实现类:
import com.spring.dao.TeacherDao;

public class TeacherDaoImple implements TeacherDao{

	public void teach() {
		System.out.println("老师在讲课");
	}
}

Student类:
import com.spring.dao.TeacherDao;

public class StudentService{

	private TeacherDao teacherDao;
	
	public void setTeacherDao(TeacherDao teacherDao) {
		this.teacherDao = teacherDao;
	}
	
	public void lean() {
		teacherDao.teach();
	}

}

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="studentService"  class="com.spring.service.StudentService">
		<property name="teacherDao"  ref="teacher"></property>
	</bean>
	<bean id="teacher" class="com.spring.dao.imple.TeacherDaoImple"></bean>
	
</beans>

测试类:
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.spring.service.StudentService;

public class StudentTest {
	private ApplicationContext atc =  new ClassPathXmlApplicationContext("Student.xml");

	@Test
	public void test1(){
		StudentService stu = atc.getBean(StudentService.class);
		stu.lean();	
	}
}
测试结果:
信息: Loading XML bean definitions from class path resource [Student.xml]
老师在讲课

Spring还支持使用JAVA来描述配置。其作用与XML是相同的。
import javax.annotation.Resource;
import org.springframework.stereotype.Component;

@Component(value="student")
public class Student implements Person{
	@Resource
	private Teacher teacher;

	public Student(Teacher teacher) {
		this.teacher = teacher;
	}
	
	public void study() {
		teacher.teach();
	}
}

尽管Student依赖与Teacher,但是他并不知道传递给他的是什么具体类型的teacher,也不知道它来自何方,只有Spring通过他的配置,能够了解这些组成部分是如何装配起来的,这样的话,就可以在不改变所依赖的类的情况下,修改依赖关系。
这里即通过Student.xml文件创建了Spring应用上下文。
    这里需要注意的是,Student类中需要有一个实际可使用的默认构造方法,如果声明了一个有参的构造方法,那么还需要声明一个无参的构造方法,否则无法自动创建bean。
    有参的构造方法时,没有声明无参构造:
public class StudentService{

	private TeacherDao teacherDao;
	
	public StudentService(TeacherDao teacherDao) {
		super();
		this.teacherDao = teacherDao;
	}

	public void setTeacherDao(TeacherDao teacherDao) {
		this.teacherDao = teacherDao;
	}
	
	public void lean() {
		teacherDao.teach();
	}

}

测试类执行结果:
警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'studentService' defined in class path resource [Student.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.spring.service.StudentService]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.spring.service.StudentService.<init>()

扫描二维码关注公众号,回复: 24451 查看本文章
所以建议保持始终显式的声明一个无参构造:
public class StudentService{

	private TeacherDao teacherDao;
	
	public StudentService() {
		super();
	}

	public StudentService(TeacherDao teacherDao) {
		super();
		this.teacherDao = teacherDao;
	}

	public void setTeacherDao(TeacherDao teacherDao) {
		this.teacherDao = teacherDao;
	}
	
	public void lean() {
		teacherDao.teach();
	}

}

测试类执行结果:
信息: Loading XML bean definitions from class path resource [Student.xml]
老师在讲课

猜你喜欢

转载自blog.csdn.net/tangmingxin0529/article/details/79950391