本文spring libs 地址:https://github.com/yizhiamumu/springlibs

Spring 能帮我们做什么

  • ①.Spring 能帮我们根据配置文件创建及组装对象之间的依赖关系。
  • ②.Spring 面向切面编程能帮助我们无耦合的实现日志记录,性能统计,安全控制。
  • ③.Spring 能非常简单的帮我们管理数据库事务。
  • ④.Spring 还提供了与第三方数据访问框架(如Hibernate、JPA)无缝集成,而且自己也提供了一套JDBC访问模板来方便数据库访问。
  • ⑤.Spring 还提供与第三方Web(如Struts1/2、JSF)框架无缝集成,而且自己也提供了一套Spring MVC框架,来方便web层搭建。
  • ⑥.Spring 能方便的与Java EE(如Java Mail、任务调度)整合,与更多技术整合(比如缓存框架)。

Spring 的优势

  • 低侵入 / 低耦合 (降低组件之间的耦合度,实现软件各层之间的解耦)
  • 声明式事务管理(基于切面和惯例)
  • 方便集成其他框架(如MyBatis、Hibernate)
  • 降低 Java 开发难度
  • Spring 框架中包括了 J2EE 三层的每一层的解决方案(一站式)

Spring IoC 是什么

  • IoC:Inverse of Control(控制反转)

读作“反转控制”更好理解。将原本在程序中手动创建对象的控制权,交由Spring框架来管理。

  • 正控:若要使用某个对象,需要自己去负责对象的创建
  • 反控:若要使用某个对象,只需要从 Spring 容器中获取需要使用的对象,不关心对象的创建过程,也就是把创建对象的控制权反转给了Spring框架

在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。

●谁控制谁?

我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象,即由Ioc容器来控制对象的创建;

●控制什么?

主要控制了外部资源获取。

●为何是反转?

有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;

为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;

●反转了什么?

依赖对象的获取被反转了。

案例1:认识springIOC

正控

1.创建员工类

Employee.java

public class Employee {

    /** 系统id */
private int id; /** 员工编号 */
private String employeeNo; /** 员工姓名 */
private String employeeName; /** 员工性别 */
private String sex; /** 出生日期 */
private Date birthDay; /** 部门编号 */
private String officeNo; /** 岗位编号 */
private String postNo; /** 入职时间 */
private Date entryTime; /** 特长 */
private String speciality; /** 兴趣爱好 */
private String hobby; /** setter and getter */
}

2.创建测试方法,并调用构造函数创建对象。

TestSpringEmp.java

public class TestSpringEmp {

    public static void main(String[] args) {
Employee emp = new Employee(); System.out.println(emp);
}
}

springIOC 控制反转

环境搭建:

1.idea 工程添加Spring相关jar包。【libs 上传至git 地址,操作方法见附录】

2.创建配置文件,可以自定义文件名spring.xml。

3.调用API。

程序思路:

1.在spring.xml中配置bean标签,IOC容器通过加载bean标签来创建对象。

2.调用API获取IOC创建的对象。

两种方式

2.1 通过id获取对象

//1.加载spring.xml配置文件
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
//2.通过id值获取对象
Employee emp = (Employee) applicationContext.getBean("emp");
System.out.println(emp);

2.2 通过运行时类获取对象

注意: 当spring.xml中配置两个Employee的bean时程序报错,因为此时两个bean都是由Employee类生成的,IOC容器无法将两个bean都返回。

必须指定一个唯一的bean

spring.xml

 <bean id="emp1" class="com.spring.model.Employee">
<property name="id" value="1"></property>
</bean> <bean id="emp2" class="com.spring.model.Employee">
<property name="id" value="2"></property>
</bean>

TestSpringEmp.java

      //1.加载spring.xml配置文件
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
//2.通过运行时类获取对象
Employee emp = applicationContext.getBean(Employee.class);
System.out.println(emp);
无参构造代码

spring.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"> <!-- 配置员工 Employee 对象-->
<bean id="emp" class="com.spring.model.Employee"></bean> </beans>

TestSpringEmp.java

import com.spring.model.Employee;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestSpringEmp { public static void main(String[] args) { //1.加载spring.xml配置文件
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
//2.通过id值获取对象
Employee emp = (Employee) applicationContext.getBean("emp");
System.out.println(emp);
}
}

第一步:加载spring.xml配置文件,生成ApplicationContext对象。

第二步:调用ApplicationContext的getBean方法获取对象,参数为配置文件中的id值。

程序在加载spring.xml时创建stu对象,通过反射机制调用无参构造函数,所有要求交给IOC容器管理的类必须有无参构造函数。

如何赋值呢?

调用无参构造只会创建对象而不会进行赋值,如何赋值呢?只需要在spring.xml中进行相关配置即可。

添加property标签:name对应属性名,value是属性的值。

注:若包含特殊字符,比如name="<一只阿木木>",使用<![CDATA[<一只阿木木>]]>进行配置。

spring.xml

     <property name="id" value="1"></property>
<property name="employeeNo" value="10001"></property>
<property name="employeeName" value="一只阿木木"></property>
<property name="sex" value="1"></property>
<property name="birthDay" value="1990-08-15"></property>
<property name="officeNo" value="7"></property>
<property name="postNo" value="1"></property>
<property name="entryTime" value="2018-07-01"></property>
<property name="speciality" value="java,python"></property>
<property name="hobby">
<value><![CDATA[<漫画>]]></value>
</property>
有参构造代码

在实体类中创建有参构造

Employee.java

public Employee(int id, String employeeNo, String employeeName) {
super();
this.id = id;
this.employeeNo = employeeNo;
this.employeeName = employeeName;
}

spring.xml

    <!-- 通过有参构造函数创建对象 -->
<bean id="emp3" class="com.spring.model.Employee">
<constructor-arg name="id" value="3"></constructor-arg>
<constructor-arg name="employeeNo" value="10001"></constructor-arg>
<constructor-arg name="employeeName" value="一只阿木木"></constructor-arg>
</bean>

除了使用name对应参数外,还可以通过下标index对应。

<!-- 通过有参构造函数创建对象 -->
<bean id="emp3" class="com.spring.model.Employee">
<constructor-arg index="0" value="3"></constructor-arg>
<constructor-arg index="1" value="10001"></constructor-arg>
<constructor-arg index="2" value="一只阿木木"></constructor-arg>
</bean>

进阶1:多个对象级联关系?

创建工作经历类 job.java

public class Job {
/** 序号 */
private int id; /** 单位名称 */
private String companyName; /** 职位名称 */
private String position; /** 工作薪水 */
private BigDecimal salary; /** setter and getter */ }

在员工Employee 类中添加工作经历job 类:

Employee.java

    /** 工作经历类*/
private Job job; /** 系统id */
private int id; /** 员工编号 */
private String employeeNo; /** 员工姓名 */
private String employeeName;

spring.xml中配置Job 对象,然后将该对象赋值给emp 对象。

spring.xml

    <!-- 创建job 对象 -->
<bean id="job" class="com.spring.model.Job">
<property name="id" value="1"></property>
<property name="companyName" value="阿木木国际集团"></property>
<property name="position" value="研发副总监"></property>
<property name="salary" value="10000.00"></property>
</bean> <!-- 创建emp对象 -->
<bean id="emp" class="com.spring.model.Employee">
<property name="id" value="1"></property>
<property name="employeeNo" value="10001"></property>
<property name="employeeName">
<value><![CDATA[<一只阿木木>]]></value>
</property>
<!-- 将job 对象赋给emp 对象-->
<property name="job" ref="job"></property>
</bean>
</bean>

在spring.xml中,通过ref属性将其他bean赋给当前bean对象,这种方式叫做依赖注入(DI),是Spring非常重要的机制,DI是将不同对象进行关联的一种方式,是IOC的具体实现方式,通常DI和IOC是紧密结合在一起的,所以一般说的IOC包括DI。

如果是集合属性如何依赖注入?

Job 类中添加List<Employee>属性。

Job.java

    /** List<Employee>属性*/
private List<Employee> employeeList;

spring.xml中配置2个emp对象,1个job对象,并将2个emp对象注入到job对象中。

spring.xml

<bean id="job" class="com.spring.model.Job">
<property name="id" value="1"></property>
<property name="companyName" value="阿木木国际集团"></property>
<property name="position" value="研发副总监"></property>
<property name="salary" value="10000.00"></property> <property name="emp">
<!-- 注入emp对象 -->
<list>
<ref bean="emp"/>
<ref bean="emp2"/>
</list>
</property>
</bean> <bean id="emp" class="com.spring.model.Employee">
<property name="id" value="1"></property>
<property name="employeeNo" value="10001"></property>
<property name="employeeName">
<value><![CDATA[<一只阿木木>]]></value>
</property>
</bean>
<bean id="emp2" class="com.spring.model.Employee">
<property name="id" value="2"></property>
<property name="employeeNo" value="10002"></property>
<property name="employeeName">
<value><![CDATA[<两只阿木木>]]></value>
</property>
</bean>

集合属性通过list标签和ref标签完成注入。ref的bean属性指向需要注入的bean对象。

IoC和DI

2004年大师级人物Martin Fowler:“依赖注入”明确描述了“被注入对象依赖IoC容器配置依赖对象”。

DI—Dependency Injection,即“依赖注入”:我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。

理解DI的关键是:“谁依赖谁,为什么需要依赖,谁注入谁,注入了什么”。

  • 谁依赖于谁:当然是应用程序依赖于IoC容器;
  • 为什么需要依赖:应用程序需要IoC容器来提供对象需要的外部资源;
  • 谁注入谁:很明显是IoC容器注入应用程序某个对象,应用程序依赖的对象;
  • 注入了什么:就是注入某个对象所需要的外部资源(包括对象、资源、常量数据)。

IoC和DI 是什么关系呢?

其实它们是同一个概念的不同角度描述。

IoC 是spring的核心,所有的类的创建、销毁都由 spring来控制,也就是说控制对象生存周期的不再是引用它的对象,而是spring。由spring来负责控制对象的生命周期和对象间的关系,这叫控制反转。

Java 1.3之后一个重要特征是反射(reflection),它允许程序在运行的时候动态的生成对象、执行对象的方法、改变对象的属性,spring就是通过反射来实现注入的。IoC的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过DI(Dependency Injection,依赖注入)来实现的。

控制的什么被反转了?就是:获得依赖对象的方式反转了。

案例2:工厂方法

IOC是典型的工厂模式,IOC通过工厂模式创建bean有两种方式:

  • 1.静态工厂方法
  • 2.实例工厂方法

一.静态工厂方法

1.1 创建工作实体类

job.java

public class Job {

    /** 序号 */
private int id; /** 单位名称 */
private String companyName; /** 职位名称 */
private String position; public Job(int id, String companyName, String position) {
super ();
this.id = id;
this.companyName = companyName;
this.position = position;
} public Job() {
super();
} @Override
public String toString() {
return "Job [id=" + id + ", companyName=" + companyName + ", postion=" + position + " ]";
} }

1.2 创建静态工厂类,静态工厂方法。

StaticFactoryJob.java

    private static Map<Integer, Job> jobs;

    static {
jobs = new HashMap<>();
jobs.put(1, new Job(1, "猫厂", "p7"));
jobs.put(2, new Job(2, "鹅厂","T2"));
} public static Job getJob(int id) {
return jobs.get(id);
}

1.3 在spring.xml中配置静态工厂。

spring.xml

    <!-- 配置静态工厂创建job对象 -->
<bean id="job1" class="com.spring.model.StaticFactoryJob" factory-method="getJob">
<constructor-arg value="1"></constructor-arg>
</bean>

factory-method指向静态方法。

constructor-arg 的value属性为调用静态方法所传的参数。

1.4 在测试类中直接获取job1对象。 TestSpringStatic.java

    public static void main(String[] args) throws SQLException {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
Job job = (Job) applicationContext.getBean("job1");
System.out.println(job);
} // 打印:Job [id=1, companyName=猫厂, postion=p7 ]

二.实例工厂方法

2.1 创建实例工厂类,工厂方法 。

InstanceFactoryJob.java

    private Map<Integer, Job> jobs;

    public  InstanceFactoryJob() {
jobs = new HashMap<>();
jobs.put(1, new Job(1, "猫厂", "p7"));
jobs.put(2, new Job(2, "鹅厂", "T2"));
}
public Job getJob(int id) {
return jobs.get(id);
}

2.2 spring.xml 中配置 bean

spring.xml

<!-- 配置实例工厂对象 -->
<bean id="jobFactory" class="com.spring.model.InstanceFactoryJob"></bean> <!-- 通过实例工厂对象创建car对象 -->
<bean id="job2" factory-bean="jobFactory" factory-method="getJob">
<constructor-arg value="2"></constructor-arg>
</bean>

2.3 在测试类中直接获取car2对象

    public static void main(String[] args) throws SQLException {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
Job job = (Job) applicationContext.getBean("job2");
System.out.println(job);
} // 打印: Job [id=2, companyName=鹅厂, postion=T2 ]

区别

静态工厂方法的方式创建job对象,不需要实例化工厂对象,因为静态工厂的静态方法,不需要创建对象即可调用。所以spring.xml只需要配置一个Job bean,而不需要配置工厂bean。

实例工厂方法创建job对象,必须先实例化工厂对象,因为调用的是非静态方法,必须通过对象调用,不能直接通过类来调用,所以spring.xml中需要先配置工厂bean,再配置Job bean。

案例3:IOC自动装载(autowire)

自动装载有两种方式:

  • byName:通过属性名自动装载
  • byType:通过属性对应的数据类型自动装载

3.1 通过属性名自动装载

1 新建BaseEmployee.java 类

public class BaseEmployee {

    /** 系统id */
private int id; /** 员工编号 */
private String employeeNo; /** 员工姓名 */
private String employeeName; /** 工作经历*/
private Job job; /** setter and getter */ @Override
public String toString() {
return "BaseEmployee [id=" + id + ", employeeNo=" + employeeNo + ", employeeName=" + employeeName + ", job=" + job + "]";
} }

2 spring.xml中配置Car bean和Person bean,并通过自动装载进行依赖注入。

spring.xml

<!--autowire="byName"表示通过匹配属性名的方式去装载对应的bean,
BaseEmployee实体类中有 job 属性,所以就将id="job"的bean注入到baseEmployee中--> <bean id="emp" class="com.spring.model.BaseEmployee" autowire="byName">
<property name="id" value="1"></property>
<property name="employeeNo" value="10001"></property>
<property name="employeeName" value="一只阿木木"></property>
</bean> <bean id="job" class="com.spring.model.StaticFactoryJob" factory-method="getJob">
<constructor-arg value="2"></constructor-arg>
</bean>

注意:通过property标签手动进行car的注入优先级更高,若两种方式同时配置,以property的配置为准。

3 测试类中获取baseEmployee 对象。

TestSpringBaseEmployee.java

public class TestSpringBaseEmployee {

    public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
BaseEmployee emp = (BaseEmployee) applicationContext.getBean("emp");
System.out.println(emp);
}
}

3.2 通过属性对应的数据类型自动装载

知识点:使用byType进行自动装载时,spring.xml中只能配置一个装载的bean。

1.spring.xml

    <bean id="emp" class="com.spring.model.BaseEmployee" autowire="byType">
<property name="id" value="1"></property>
<property name="employeeNo" value="10001"></property>
<property name="employeeName" value="一只阿木木"></property>
</bean> <bean id="job" class="com.spring.model.StaticFactoryJob" factory-method="getJob">
<constructor-arg value="2"></constructor-arg>
</bean> <!--<bean id="job2" class="com.spring.model.StaticFactoryJob" factory-method="getJob">
<constructor-arg value="2"></constructor-arg>
</bean>-->

2.测试类中获取person对象

TestSpringBaseEmployee.java

// 打印:BaseEmployee [id=1, employeeNo=10001, employeeName=一只阿木木, job=Job [id=2, companyName=鹅厂, postion=T2 ]]

案例4:程序架构MVC 分层

经典三层架构:Controller层,Service层,DAO层。

有两种方式:

  • 基于xml配置文件
  • 基于注解

4.1 基于 xml 配置

model 层实体类:

BaseEmployee.java

public class BaseEmployee {

    /** 系统id */
private int id; /** 员工编号 */
private String employeeNo; /** 员工姓名 */
private String employeeName; public BaseEmployee(int id, String employeeNo, String employeeName) {
super();
this.id = id;
this.employeeNo = employeeNo;
this.employeeName = employeeName;
}
public BaseEmployee() {
super();
} @Override
public String toString() {
return "BaseEmployee [id=" + id + ", employeeNo=" + employeeNo + ", employeeName=" + employeeName + "]";
} /** setter and getter */ }
Dao 层接口

BaseEmployeeDao.java

    public interface BaseEmployeeDao {
public BaseEmployee getBaseEmpById(int id);
}

BaseEmployeeDaoImpl.java

public class BaseEmployeeDaoImpl implements BaseEmployeeDao{

    private static Map<Integer,BaseEmployee> baseEmployee;

    static{
baseEmployee = new HashMap<Integer,BaseEmployee>();
baseEmployee.put(1, new BaseEmployee(1, "10001", "一只阿木木"));
baseEmployee.put(2, new BaseEmployee(2, "10002", "两只阿木木"));
baseEmployee.put(3, new BaseEmployee(3, "10003", "三只阿木木"));
} @Override
public BaseEmployee getBaseEmpById(int id) {
// TODO Auto-generated method stub
return baseEmployee.get(id);
}
}
Service 层

创建BaseEmployeeService 接口以及实现类BaseEmployeeServiceImpl。

BaseEmployeeService

public interface BaseEmployeeService {
public BaseEmployee getBaseEmpById(int id);
}

BaseEmployeeServiceImpl.java

public class BaseEmployeeServiceImpl implements BaseEmployeeService {

    private BaseEmployeeDAO baseEmployeeDAO;

    public BaseEmployeeDAO getBaseEmployeeDAO() {
return baseEmployeeDAO;
} public void setBaseEmployeeDAO(BaseEmployeeDAO baseEmployeeDAO) {
this.baseEmployeeDAO = baseEmployeeDAO;
} @Override
public User getBaseEmpById(int id) {
// TODO Auto-generated method stub
return baseEmployeeDAO.getBaseEmpById(id);
}
}
Controller 层

BaseEmployeeController.java

public class BaseEmployeeController {

    private BaseEmployeeService baseEmployeeService;

    public BaseEmployeeService getBaseEmployeeService() {
return baseEmployeeService;
} public void setBaseEmployeeService(BaseEmployeeService baseEmployeeService) {
this.baseEmployeeService = baseEmployeeService;
} public BaseEmployee getBaseEmpById(int id){
return baseEmployeeService.getBaseEmpById(id);
}
}
spring.xml

在spring.xml配置Controller,Service,DAO,并完成依赖注入。 spring.xml

    <!-- 配置BaseEmployeeController -->
<bean id="baseEmployeeController" class="com.spring.controller.BaseEmployeeController">
<property name="baseEmployeeService" ref="baseEmployeeService"></property>
</bean> <!-- 配置BaseEmployeeService -->
<bean id="baseEmployee" class="com.spring.service.BaseEmployeeServiceImpl">
<property name="baseEmployeeDAO" ref="baseEmployeeDAO"></property>
</bean> <!-- 配置BaseEmployeeDAO -->
<bean id="baseEmployeeDAO" class="com.spring.dao.BaseEmployeeDaoImpl"></bean>
测试

TestSpringBaseEmployee.java

    public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
BaseEmployeeController baseEmployeeController = (BaseEmployeeController) applicationContext.getBean("baseEmployeeController");
BaseEmployee baseEmployee = baseEmployeeController.getBaseEmpById(1);
System.out.println(baseEmployee);
}

4.2基于注解的方式

4.2.1 默认byType 方式

第一步:将Controller,Service,DAO类扫描到IOC容器中。

第二步:在类中设置注解完成依赖注入。

1 修改 spring.xml

知识点:引入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-4.0.xsd"> <!-- 将类扫描到IOC容器中 -->
<context:component-scan base-package="com.spring"></context:component-scan>
</beans>

2 修改DAOImpl

改动:在类名处添加@Repository注解,表示该类是数据接口层。

    @Repository
public class BaseEmployeeDaoImpl implements BaseEmployeeDao{ private static Map<Integer,BaseEmployee> baseEmployee; static{
baseEmployee = new HashMap<Integer,BaseEmployee>();
baseEmployee.put(1, new BaseEmployee(1, "10001", "一只阿木木"));
baseEmployee.put(2, new BaseEmployee(2, "10002", "两只阿木木"));
baseEmployee.put(3, new BaseEmployee(3, "10003", "三只阿木木"));
} @Override
public BaseEmployee getBaseEmpById(int id) {
// TODO Auto-generated method stub
return baseEmployee.get(id);
}
}

3 修改ServiceImpl。

  • 在类名处添加@Service注解,表示该类是业务层。
  • DAO属性出添加@Autowired注解,表示IOC容器自动完成装载,默认是byType的方式。
@Service
public class BaseEmployeeServiceImpl implements BaseEmployeeService{ @Autowired
private BaseEmployeeDAO baseEmployeeDAO; @Override
public BaseEmployee getBaseEmpById(int id) {
// TODO Auto-generated method stub
return baseEmployeeDAO.getBaseEmpById(id);
}
}

4 修改 Controller类,添加注解。

有两处改动:

  • 在类名处添加@Controller注解,表示该类作为一个控制器。
  • Service属性出添加@Autowired注解,表示IOC容器自动完成装载,默认是byType的方式。

BaseEmployeeControler.java

@Controller
public class BaseEmployeeController { @Autowired
private BaseEmployeeService baseEmployeeService; public BaseEmployee getBaseEmpById(int id){
return baseEmployeeService.getBaseEmpById(id);
} }

4.2.2 ByName

自动装载除了byType的方式,还可以结合@Qualifier注解, 使用byName的方式。

知识点:@Qualifier()中的值必须与@Service()中的值一致,才能完成自动装载。

BaseEmployeeControler.java

@Controller
public class BaseEmployeeController { @Autowired
@Qualifier("baseEmployeeService")
private BaseEmployeeService baseEmployeeService; public BaseEmployee getBaseEmpById(int id){
return baseEmployeeService.getBaseEmpById(id);
} }

基于注解的方式我们并没有给bean设置id,byName的方式是通过属性名去匹配对应bean的id属性值。

添加注解时,类名首字母小写之后的值就是id的默认值。IOC容器中默认赋值,BaseEmployeeService bean的id=baseEmployeeService,与Controller中的属性名一致

@Service
public class BaseEmployeeServiceImpl implements BaseEmployeeService

修改

BaseEmployeeService bean的id=sortBaseEmployeeService。

Service 层
@Service("sortBaseEmployeeService")
public class BaseEmployeeServiceImpl implements BaseEmployeeService{ @Autowired
private BaseEmployeeDAO baseEmployeeDAO; @Override
public BaseEmployee getBaseEmpById(int id) {
// TODO Auto-generated method stub
return baseEmployeeDAO.getBaseEmpById(id);
}
}
Controller 层

Controller中的Service属性也需要去匹配name=sortBaseEmployeeService的bean,所以设置@Qualifier("sortBaseEmployeeService")。

@Controller
public class BaseEmployeeController { @Autowired
@Qualifier("sortBaseEmployeeService")
private BaseEmployeeService baseEmployeeService; public BaseEmployee getBaseEmpById(int id){
return baseEmployeeService.getBaseEmpById(id);
} }

小结

IOC概念

spring IoC的思想:依赖注入就是A开放接口,将B传递进来(注入);控制反转,AB双方不相互依赖,整个活动的进行由第三方负责管理。

控制反转,由容器创建组件对象,然后注入参数建立应用关系。

例如EmployeeDao调用Data,由Spring容器创建EmployeeDao和Data对象,然后再由容器将Data对象注入给EmployeeDao中的属性。

Data注入途径可以是set方法,也可以是带参数构造器等。

编写规则

EmployeeDao类在编写时,需要定义一个set方法或带参数构造器,参数类型为Data。

public class EmployeeDao {
private Data data; //1 set 方法注入
private void setData(Data data) {
this.data = data;
} //2 带参数构造器注入
private EmployeeDao(Data data) {
this.data = data;
} }

配置原理

    <!--原理,利用反射创建对象(无参构造器), 然后利用反射注入参数-->
<bean id="" class="">
<property name="" value|ref=""></property>
</bean> <!--原理:利用反射直接调用带参数构造器创建对象-->
<bean id="" class="">
<constructor-arg index="" value|ref=""></constructor-arg>
</bean>

装配 Spring Bean 小结

集合注入总结:

List 属性使用 <list> 元素定义注入,使用多个 <ref> 元素的 Bean 属性去引用之前定义好的 Bean

<property name="list">
<list>
<ref bean="bean1"/>
<ref bean="bean2"/>
</list>
</property>

Map 属性使用 <map> 元素定义注入,使用多个 <entry> 元素的 key-ref 属性去引用之前定义好的 Bean 作为键,而用 value-ref 属性引用之前定义好的 Bean 作为值

<property name="map">
<map>
<entry key-ref="keyBean" value-ref="valueBean"/>
</map>
</property>

Set 属性使用 <set> 元素定义注入,使用多个 <ref> 元素的 bean 去引用之前定义好的 Bean

<property name="set">
<set>
<ref bean="bean"/>
</set>
</property>

命名空间装配

需要引入其声明

C命名空间

<!-- 引入 c-命名空间之前 -->
<bean name="emp1" class="spring.Employee">
<constructor-arg name="id" value="1" />
<constructor-arg name="name" value="姓名1"/>
</bean> <!-- 引入 c-命名空间之后 -->
<bean name="emp2" class="spring.Employee"
c:id="2" c:name="姓名2"/> <!--参数的索引。XML中不允许数字作为属性的第一个字符,因此添加一个下划线来作为前缀。-->
<bean name="emp2" class="spring.Employee"
c:_0="2" c:_1="姓名2"/>

p-命名空间

c-命名空间通过构造器注入的方式来配置 bean,p-命名空间则是用setter的注入方式来配置 bean

<!-- 引入p-命名空间之前 -->
<bean name="emp1" class="spring.Employee">
<property name="id" value="1" />
<property name="name" value="姓名1"/>
</bean> <!-- 引入p-命名空间之后 -->
<bean name="emp2" class="spring.Employee"
p:id="2" p:name="姓名2"/> <!--属性需要注入其他 Bean 的话也可以在后面跟上 -ref-->
<bean name="emp2" class="spring.Employee"
p:id="2" p:name="姓名2" p:cdCard-ref="cdCard1"/>

util-命名空间

工具类的命名空间,可以简化集合类元素的配置

<!-- 引入util-命名空间之前 -->
<property name="list">
<list>
<ref bean="bean1"/>
<ref bean="bean2"/>
</list>
</property> <!-- 引入util-命名空间之后 -->
<util:list id="list">
<ref bean="bean1"/>
<ref bean="bean2"/>
</util:list>

引入配置文件

【src】文件下新建一个 bean.xml

在 applicationContext.xml 文件中写入:

<import resource="bean.xml" />

自动装配 autowired

  • 理解: @Autowired 注解表示在 Spring IoC 定位所有的 Bean 后,再根据类型寻找资源,然后将其注入。
  • 过程: 定义 Bean ——> 初始化 Bean(扫描) ——> 根据属性需要从 Spring IoC 容器中搜寻满足要求的 Bean ——> 满足要求则注入
  • 问题: IoC 容器可能会寻找失败,此时会抛出异常(默认情况下的Spring IoC 容器会认为一定要找到对应的 Bean 来注入到这个字段,但有些时候并不是一定需要,比如日志)
  • 解决: 通过配置项 required 来改变,比如 @Autowired(required = false)

一切需要 Spring IoC 去寻找 Bean 资源的地方都可以用到

自动装配的歧义性(@Primary和@Qualifier)

@Primary 注解:

  • 首要的。当 Spring IoC 检测到有多个相同类型的 Bean 资源的时候,会优先注入使用该注解的类。
  • 问题:只是解决了首要的问题,但是并没有选择性的问题

@Qualifier 注解:

  • 产生歧义性的一个重要的原因是 Spring 在寻找依赖注入的时候是按照类型注入引起的。除了按类型查找 Bean,Spring IoC 容器最底层的接口 BeanFactory 还提供了按名字查找的方法,如果按照名字来查找和注入不就能消除歧义性了吗?
  • 使用方法: 指定注入名称为 "source1" 的 Bean 资源
/* 包名和import */
public class SpringZhujie {
......
@Autowired
@Qualifier("source1")
public void setSource(Source source) {
this.source = source;
}
}

使用@Bean 装配 Bean

问题:

通过 @Component 注解来装配 Bean ,并且只能注解在类上,当你需要引用第三方包的(jar 文件),而且往往并没有这些包的源码,这时候将无法为这些包的类加入 @Component 注解,让它们变成开发环境中的 Bean 资源。

解决方案:
  • 1.自己创建一个新的类来扩展包里的类,然后再新类上使用 @Component 注解,但这样很 low
  • 2.使用 @Bean 注解,注解到方法之上,使其成为 Spring 中返回对象为 Spring 的 Bean 资源。

@Configuration 注解相当于 XML 文件的根元素,解析其中的 @Bean 注解

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; @Configuration
public class TestBean { @Bean(name = "testBean")
public String test() {
String str = "测试@Bean注解";
return str;
}
}

使用方法

  1. 引入spring 开发包
  2. 配置文件.xml
  3. 编写组件,定义到xml 配置中
  4. 创建窗口对象,调用 getBean 获取Bean 对象使用
 
 

由于Java语言本身的类反射功能,使得仅凭一个配置文件,就能魔法般地实例化并装配好程序所用的Bean。容器启动时,Spring根据配置文件的描述信息,自动实例化Bean并完成依赖关系的装配,从容器中即可返回准备就绪的Bean实例,后续可直接使用之。

本文spring libs 地址:https://github.com/yizhiamumu/springlibs


公众号:一只阿木木

博客园:http://www.cnblogs.com/yizhiamumu/

github : https://github.com/yizhiamumu/

案例学编程系列:案例认识 Spring IOC的更多相关文章

  1. 【SSH系列】深入浅出spring IOC中三种依赖注入方式

    spring的核心思想是IOC和AOP,IOC-控制反转,是一个重要的面向对象编程的法则来消减计算机程序的耦合问题,控制反转一般分为两种类型,依赖注入和依赖查找,依赖什么?为什么需要依赖?注入什么?控 ...

  2. Spring系列(二):Spring IoC/DI的理解

    这几天重新学习了一下Spring,在网上找了相关的ppt来看,当看到Spring IoC这一章节的时候,先大致浏览了一下内容,有将近50页的内容,内心窃喜~QAQ~,看完这些内容能够对IoC有更深层次 ...

  3. Spring系列(三):Spring IoC中各个注解的理解和使用

    原文链接:1. http://www.cnblogs.com/xdp-gacl/p/3495887.html       2. http://www.cnblogs.com/xiaoxi/p/5935 ...

  4. Spring IOC(二)容器初始化

    本系列目录: Spring IOC(一)概览 Spring IOC(二)容器初始化 Spring IOC(三)依赖注入 Spring IOC(四)总结 目录 一.ApplicationContext接 ...

  5. Spring IOC(三)依赖注入

    本系列目录: Spring IOC(一)概览 Spring IOC(二)容器初始化 Spring IOC(三)依赖注入 Spring IOC(四)总结 目录 1.AbstractBeanFactory ...

  6. Spring IOC(一)概览

    Spring ioc源码解析这一系列文章会比较枯燥,但是只要坚持下去,总会有收获,一回生二回熟,没有第一次,哪有下一次... 本系列目录: Spring IOC(一)概览 Spring IOC(二)容 ...

  7. Spring框架系列(3) - 深入浅出Spring核心之控制反转(IOC)

    在Spring基础 - Spring简单例子引入Spring的核心中向你展示了IoC的基础含义,同时以此发散了一些IoC相关知识点; 本节将在此基础上进一步解读IOC的含义以及IOC的使用方式.@pd ...

  8. Spring框架系列(4) - 深入浅出Spring核心之面向切面编程(AOP)

    在Spring基础 - Spring简单例子引入Spring的核心中向你展示了AOP的基础含义,同时以此发散了一些AOP相关知识点; 本节将在此基础上进一步解读AOP的含义以及AOP的使用方式.@pd ...

  9. Spring框架系列(6) - Spring IOC实现原理详解之IOC体系结构设计

    在对IoC有了初步的认知后,我们开始对IOC的实现原理进行深入理解.本文将帮助你站在设计者的角度去看IOC最顶层的结构设计.@pdai Spring框架系列(6) - Spring IOC实现原理详解 ...

随机推荐

  1. 页面添加锚点后如何点击不改变URL?

    直接奔主题,前端简单地锚点实现方法大家都会,无非就是在把 a 标签的 href 写成想要跳到的元素的id ,比如点击 <a href="#box"></a> ...

  2. 4--TestNG测试报告

    第一:自带测试报告(略) 第二:Reportng测试报告(略) 第三:ExtentReport--extentreports.com (1) pom.xml:不是总的pom,是文件夹下的pom < ...

  3. MHA(上)

    一.mysql-mha环境准备 1.准备工作 1.1 实验环境: 1.2 软件包 用到的所有包 链接:https://pan.baidu.com/s/19tiKXNEW4C6oWi9OFmcDYA 提 ...

  4. Python基础学习总结(持续更新)

    https://www.cnblogs.com/jin-xin/articles/7459977.html 嗯,学完一天,白天上班,眼睛要瞎了= = DAY1 1,计算机基础. CPU:相当于人的大脑 ...

  5. read读文件

    FILE *fp=fopen("F:\\QQBrowser_Setup_DNF.exe", "rb"); fseek(fp, , SEEK_END); long ...

  6. 使用linux命令行调整非图形界面分辨率

    第一步,调整linux内核显示参数: 打开内核菜单配置列表文件: vi /boot/grub/menu.lst 或者 vi /boot/grub/gurb.conf 在kernel设置一行末尾添加: ...

  7. JVM学习一:JVM运行时数据区

    注:此图适合JDK 7之前的版本,JDK 8开始增加了元数据空间,内存区结构有所变化(JDK 7将字符串常量池移除了永久代,JDK 8去永久代,迎元数据空间metaspace) 1.程序计数器:程序计 ...

  8. curl传输数据时遇到的问题整理

    1.get传参,参数带有空格的传输方式 因为使用get传输的时候,有的参数可能存在有空格,为了避免传输是错误是字符替代“%20” 或者使用函数转译一下参数http_build_query($param ...

  9. react+umi+dva+antd中dva的数据流图解

  10. VS Code引用 vue/cli

    npm i @vue/cli -g    引用cli脚手架 3.0版本 下载好后 找个空文件夹  vue create myvue 创建vue项目   myvue是自己项目名称 Your connec ...