博客
关于我
Spring学习(三):IOC容器详解
阅读量:80 次
发布时间:2019-02-25

本文共 11094 字,大约阅读时间需要 36 分钟。

文章目录

什么是IOC

Inversion of Control的缩写,中文译为控制反转,简单来说就是把对象创建和对象之间的调用过程,交给 Spring 进行管理。

创建对象实例的控制权从代码控制剥离到IOC容器控制,实际就是你在xml文件控制,侧重于原理

底层原理

  • XML解析
    使用dom4j解析
  • 工厂模式
  • 反射创建类对象
Class clazz=Class.forName(classValue);UserService service=clazz.newInstance();return service;

XML注入实现IOC

注入常规类型属性

set方法注入

  • 第一步 在类中定义属性和对应的 set 方法
  • 第二步 在XML文件中添加property标签

有参构造注入

  • 第一步 在类中定义有参构造方法
  • 第二步 在XML文件中添加constructor-arg标签

P空间注入(了解)

  • 第一步 在类中定义属性和对应的 set 方法
  • 第二步 修改XML文件
    在beans中添加xmlns:p属性;在bean中添加p:name属性

注入特殊类型属性

空值

特殊符号

  • 方法一 把<>进行转义

  • 把带特殊符号内容写到 CDATA

    >]]>

外部Bean

现有类UserService、接口UserDao、类UserDaoImpl,其中UserDaoImpl实现了接口UserDao。代码结构如下:

src    │  bean.xml    │    └─com        └─spring5            │  Test.java             │            ├─dao            │      UserDao.java            │      UserDaoImpl.java            │            └─service                    UserService.java

如果类UserService要调用类UserDaoImpl的方法,传统做法是创建UserDao对象然后调用其方法,这种做法耦合太高。用spring注入的步骤如下:

  • 在UserService中创建属性UserDao,并写好set方法
  • 在XML中配置UserService和UserDao对象
  • 通过property标签注入UserDao对象

示例代码如下:

接口UserDao:

public interface UserDao {       public void update();}

类UserDaoImpl:

public class UserDaoImpl implements UserDao {       @Override    public void update() {           System.out.println("I am dao update...");    }}

类UserService:

public class UserService {      private UserDao userDao;    public void setUserDao(UserDao userDao) {           this.userDao = userDao;    }    @Test    public void add(){           System.out.println("I am service add...");        userDao.update();    }}

bean.xml:

内部Bean和级联配置

简单来说就是bean标签里面嵌套bean标签。在员工和部门,一个部门有多个员工,一个员工属于一个部门。示例代码如下:

Dept类:

public class Dept {   	private String  dname;	public void setDname(String dname) {   		this. dname = dname;	}}

Emp类

public class Emp {   	private String  ename;	private String  gender;	//员工属于某一个部门,使用对象形式表示	private Dept  dept;	public void setDept(Dept dept) {   		this. dept = dept;	}	public void setEname(String ename) {   		this. ename = ename;	}	public void setGender(String gender) {   		this. gender = gender;	}}
内部Bean配置
级联配置

Emp类需要生成getDep的方法

public Dept getDept(){   	return dept;}

XML文件中dept.dname获取属性

注入集合属性

普通注入

新建类User,包含集合属性和相关set方法

public class User {       private String[]  arrs;// 数组    private List
list;// list private Map
maps;// map private Set
sets;// set public void setArrs(String[] arrs) { this.arrs = arrs; } public void setList(List
list) { this.list = list; } public void setMaps(Map
maps) { this.maps = maps; } public void setSets(Set
sets) { this.sets = sets; }}

XML配置

JAVA课程
mySQL课程
张三
李四
MySQL
MySQL
Oracle
Oracle

注入对象集合

Dept类

public class Dept {       //部门有多个员工    private List
empList; public void setEmpList(List
empList) { this.empList = empList; }}

Emp类

public class Emp {       private String eName;    public void seteName(String eName) {           this.eName = eName;    }}

XML配置

自动装配

Spring可以根据属性名称或者类型进行自动装配,使用byType时相同类型的Bean不能配置多个

外部属性文件

一、创建外部属性文件jdbc.properties,填写数据库信息,key随便写

prop.driverClass=com.mysql.jdbc.Driverprop.url=jdbc:mysql://localhost:3306/userDbprop.userName=rootprop.password=root

二、把外部 properties 属性文件引入到 spring 配置文件中

  • 引入 context 名称空间

    xmlns:context=“http://www.springframework.org/schema/context”
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring- - context.xsd"

  • 在 spring 配置文件使用标签引入外部属性文件

工厂Bean

Spring 有两种类型:普通 bean和工厂bean(FactoryBean)。普通 bean在配置文件中定义的bean类型和返回类型一样,而工厂bean在配置文件定义 bean类型可以和返回类型不一样。实现工厂Bean的步骤如下:

  • 第一步 创建类,让这个类作为工厂 bean,实现FactoryBean接口
  • 第二步 重写接口里面的方法,在方法中定义返回的bean类型

示例代码如下:

MyBean和User类

public class MyBean implements FactoryBean
{ @Override public User getObject() throws Exception { User user = new User(); user.setName("张三"); return user; } @Override public Class
getObjectType() { return null; } @Override public boolean isSingleton() { return false; }}public class User { private String name; public void setName(String name) { this.name = name; } public void test(){ System.out.println("I am test..."); }}

bean.xml

Test类

public class Test {       @org.junit.Test    public void test() {           //1 加载 spring 配置文件        ApplicationContext context =                new ClassPathXmlApplicationContext("bean.xml");        //2 获取配置创建的对象        User user = context.getBean("myBean", User.class);        System.out.println(user);        user.test();    }}

运行结果:

com.spring5.User@42d8062c
I am test…

Bean的作用域

作用域 说明
单例(singleton) 默认)每一个Spring IoC容器都拥有唯一的一个实例对象
原型(prototype) 一个Bean定义,任意多个对象
请求(request) 一个HTTP请求会产生一个Bean对象,也就是说,每一个HTTP请求都有自己的Bean实例。只在基于web的Spring ApplicationContext中可用
会话(session) 限定一个Bean的作用域为HTTPsession的生命周期。同样,只有基于web的Spring ApplicationContext才能使用
全局会话(global session) 限定一个Bean的作用域为全局HTTPSession的生命周期。通常用于门户网站场景,同样,只有基于web的Spring ApplicationContext可用

Bean的生命周期

  • 第一步,执行无参构造创建Bean实例

  • 第二步,调用类的set方法设置属性值

  • 第三步,调用预初始化方法postProcessBeforeInitialzation()

    需要有Bean实现了BeanPostProcessor接口

  • 第四步,调用bean的初始化的方法

    需要在XML的bean属性中进行配置

    init-method="初始化调用方法名"
  • 第五步,调用后初始化方法postProcessAfterInitialization()

    需要有Bean实现了BeanPostProcessor接口

  • 第六步,对象获取到了,bean可以使用了

  • 第七步,当容器关闭时调用bean的销毁的方法

    需要在XML的bean属性中进行配置

    destroy-method="销毁调用方法名"

实例代码如下:

User类

public class User {       private String name;    public User() {           System.out.println("第一步 执行无参构造创建Bean实例");    }    public void setName(String name) {           this.name = name;        System.out.println("第二步 调用set方法设置属性值");    }    public void initMethod(){           System.out.println("第四步 调用bean的初始化的方法");    }    public void destroyMethod(){           System.out.println("第七步 当容器关闭时调用bean的销毁的方法");    }    public void test(){           System.out.println("I am test...");    }}

MyBeanPost类

public class MyBeanPost implements BeanPostProcessor {       @Override    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {           System.out.println("第三步,调用预初始化方法postProcessBeforeInitialzation()");        return bean;    }    @Override    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {           System.out.println("第五步,调用后初始化方法postProcessAfterInitialization()");        return bean;    }}

Test类

public class Test {       @org.junit.Test    public void test() {           //1 加载 spring 配置文件        ClassPathXmlApplicationContext context =                new ClassPathXmlApplicationContext("bean.xml");        //2 获取配置创建的对象        User user = context.getBean("user", User.class);        System.out.println(user);        System.out.println("第六步 对象获取到了,bean可以使用了");        user.test();        context.close();    }}

bean.xml

注解方式实现IOC

注解概述

  • 注解是代码特殊标记
    语法:@注解名称(属性名称=属性值, 属性名称=属性值…)
  • 怎么用注解
    注解可以用在类、方法和属性上面
  • 使用注解目的
    简化 xml 配置

Spring针对 Bean管理中创建对象提供的注解

  • @Component
  • @Service
  • @Controller
  • @Repository
    上面四个注解功能是一样的,都可以用来创建 bean 实例,在服务层用@Service、在控制层用@Controller只是方便管理

实现对象创建

  • 第一步 引入依赖
    把spring-aop-5.2.6.RELEASE.jar包引入到IDEA中
  • ​ 第二步 开启组件扫描
    需要引入context名称空间:xmlns:context=“http://www.springframework.org/schema/context”、http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"
  • 第三步 创建类,在类上面添加注解
    注解中的value值可以省略,默认值是类名首字母小写
@Component(value = "userService")public class UserService {       public void add(){           System.out.println("I am UserService add...");    }}

扫描细节配置

  • 不加use-default-filters="false"表示会扫描包下面的所有注解
  • context:include-filter 配置扫描哪些内容
  • context:exclude-filter配置不扫描哪些内容

示例一

示例二

实现属性注入

@Autowired、@Qualifier和@Resource用于"对象"属性,@Value用于普通属性。

@Autowired

现有类UserService、接口UserDao、类UserDaoImpl,其中UserDaoImpl实现了接口UserDao。代码结构如下:

src    │  bean.xml    │    └─com        └─spring5            │  Test.java             │            ├─dao            │      UserDao.java            │      UserDaoImpl.java            │            └─service                    UserService.java

如果类UserService要调用类UserDaoImpl的方法,用spring注解实现的步骤如下:

  • 在 UserService和 UserDaoImpl类添加创建对象注解
  • 在 UserService类添加UserDao类型属性,并在属性上面使用注解

示例代码如下:

接口UserDao:

public interface UserDao {       public void update();}

类UserDaoImpl:

@Repository(value = "userDaoImpl")public class UserDaoImpl implements UserDao {       @Override    public void update() {           System.out.println("I am dao update...");    }}

类UserService:

@Service(value = "userService")public class UserService {       @Autowired    private UserDao userDao;    public void add(){           System.out.println("I am UserService add...");        userDao.update();    }}

bean.xml:

@Qualifier

@Qualifier注解是根据名称进行注入。如果接口有很多实现类用@Autowired就不行,和@Qualifier一起使用就可以解决。使用示例:

@Autowired@Qualifier(value = "userDaoImpl2")private UserDao userDao;

@Resource

@Resource是javax.annotation.Resource包中的注解,既可以根据名称注入又可以根据类型注入。

示例:

// 根据类型注入@Resourceprivate UserDao userDao;// 根据名称注入@Resource(name = "userDaoImpl")private UserDao userDao;

@Value

@Value用于普通属性。

注入普通属性
@Value(value = "张三丰")private String name;
注入List

步骤如下:

  • 在src下简历属性文件application.properties
my.names=zhangsan,lisi,wangwu,zhaoli
  • 在类UserService中添加@PropertySource和@Value注解
@Service(value = "userService")@PropertySource(value="classpath:application.properties")public class UserService {       @Resource(name = "userDaoImpl")    private UserDao userDao;    @Value("#{'${my.names}'.split(',')}")    private List
names; public void add(){ System.out.println("I am UserService add..."); userDao.update(); }}

完全注解开发

  • 创建配置类,替代 xml 配置文件
@Configuration@ComponentScan(basePackages = {   "com.spring5"})public class SpringConfig {   }
  • 编写测试类
    用AnnotationConfigApplicationContext加载spring的java配置文件
@org.junit.Testpublic void test() {       //1 加载spring的java配置文件    ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);    //2 获取创建的对象    UserService userService = context.getBean("userService", UserService.class);    userService.add();}

这个过程在实际环境中会用SpringBoot替代。

转载地址:http://pis.baihongyu.com/

你可能感兴趣的文章
MySQL一个表A中多个字段关联了表B的ID,如何关联查询?
查看>>
MYSQL一直显示正在启动
查看>>
MySQL一站到底!华为首发MySQL进阶宝典,基础+优化+源码+架构+实战五飞
查看>>
MySQL万字总结!超详细!
查看>>
Mysql下载以及安装(新手入门,超详细)
查看>>
MySQL不会性能调优?看看这份清华架构师编写的MySQL性能优化手册吧
查看>>
MySQL不同字符集及排序规则详解:业务场景下的最佳选
查看>>
Mysql不同官方版本对比
查看>>
MySQL与Informix数据库中的同义表创建:深入解析与比较
查看>>
mysql与mem_细说 MySQL 之 MEM_ROOT
查看>>
MySQL与Oracle的数据迁移注意事项,另附转换工具链接
查看>>
mysql丢失更新问题
查看>>
MySQL两千万数据优化&迁移
查看>>
MySql中 delimiter 详解
查看>>
MYSQL中 find_in_set() 函数用法详解
查看>>
MySQL中auto_increment有什么作用?(IT枫斗者)
查看>>
MySQL中B+Tree索引原理
查看>>
mysql中cast() 和convert()的用法讲解
查看>>
mysql中datetime与timestamp类型有什么区别
查看>>
MySQL中DQL语言的执行顺序
查看>>