IOC容器

  • 什么是IOC容器
  • IOC容器中的Bean
  • 小试牛刀
    • 搭建Spring5环境
    • 写一个HelloWorld
  • IOC底层原理
  • IOC的Bean管理
    • 基于 xml 方式创建对象
    • 基于 xml 方式的属性注入
      • set方法注入
      • 构造器注入
    • 基于XML方式注入其他类型的属性
      • 注入null
      • 注入特殊符号
      • 注入引用数据类型
        • 使用外部bean
        • 使用内部bean
        • 级联赋值
      • 注入集合类型
      • 设置集合属性对象类型的值
      • 提取集合类型属性的注入部分
      • 普通bean和工厂bean
      • bean的作用域
      • bean的生命周期
      • XML的自动装配
      • 外部属性文件
    • 基于注解方式创建对象
    • 基于注解方式注入属性
      • @Autowired
      • @Qualifier
      • @Resource
      • @Value
    • 完全注解开发

什么是IOC容器

IOC全称Inversion of Control,直译为控制反转,它是具有依赖注入功能的容器,负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。应用程序无需直接在代码中new相关的对象,应用程序由IOC容器进行组装。在Spring中BeanFactory是IOC容器的实际代表者。使用IOC的目的是为了降低耦合度。

IOC容器中的Bean

Bean就是由Spring容器初始化、装配及管理的对象。那IOC怎样确定如何实例化Bean、管理Bean之间的依赖关系以及管理Bean呢?先让我们来做个简单的例子。

小试牛刀

搭建Spring5环境

打开Inteillj然后new一个Java项目:

    导入相关的jar包:

写一个HelloWorld

写一个简单的Person类:

package com.jackma.spring5;public class Person {public void sayHello(){System.out.println("Hello World");}
}

创建一个xml文件,用来告诉Spring的IOC容器应该如何创建并组装Bean,其中id是一个Bean的唯一标识,class表示类全路径:

<?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 name="person" class="com.jackma.spring5.Person"></bean>
</beans>

然后写一个单元测试方法:

public class MySpringTest {@Testpublic void test(){ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");Person person = context.getBean("person", Person.class);person.sayHello();}
}

测试:

IOC底层原理

先来看个实例:假设有两个类,UserService和UserDao,UserDao中有一个add()方法,我们要在UserService调用它,那么使用原始的方式是这样实现的:

public class UserDao {public void add(){System.out.println("add.......");}
}
public class UserService {public void execute(){UserDao userDao = new UserDao();userDao.add();}
}

但原始的方法会存在一个问题,即耦合度太高了,UserService和UserDao关系过于紧密,解决方法是提供一个工厂类,把new userDao的工作交给工厂类,实现解耦:

public class UserFactory {public static UserDao getuserDao(){return new userDao();}
}
public class UserService {public void execute(){UserDao userDao = UserFactory.getuserDao();userDao.add();}
}

Spring的IOC的底层原理使用到了xml解析、工厂模式和反射:
    第一步先配置xml文件:

<bean id="userdao" class="com.jackma.spring5.dao.UserDao"></bean>

第二步是Spring会根据User类和userDao类提供一个UserFactory类,且类中根据反射来实现创建userDao对象:

public class UserFactory {public static UserDao getuserDao(){String classValue = class属性值; // 该值通过xml解析得到Class clazz = Class.forName(classValue);return (UserDao)clazz.newInstance();}
}

IOC的Bean管理

Bean管理指的是Spring创建对象和Spring注入属性两个操作,实现方式有两种:
        ①:基于 xml 配置文件方式实现
        ②:基于注解方式实现

基于 xml 方式创建对象

像上面的HelloWorld例子使用的就是 xml 方式创建对象,在spring配置文件中,使用bean标签,标签里面添加对应属性,就可以实现对象创建,且创建对象时候,默认也是执行无参数构造方法完成对象创建。

基于 xml 方式的属性注入

基于 xml 方式的属性注入有两种方式:set方法注入和构造器注入,还是拿User类来举例 。

set方法注入

先在User类中添加两个属性,然后记得要提供对应的set方法:

public class User {private int id;private String name;public void setId(int id) {this.id = id;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "User{" +"id=" + id +", name='" + name + '\'' +'}';}public void add(){System.out.println("add......");}
}

然后在配置文件中添加bean:

<?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">
<!--    set 方法注入--><bean id="user"  class="com.jackma.spring5.User" ><property name="id" value="1"></property><property name="name" value="Jackma"></property>
</bean>
</beans>

然后测试:

@Testpublic void test1(){ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");User user = context.getBean("user", User.class);System.out.println(user);user.add();}

构造器注入

要在User类中添加构造器方法:

package com.jackma.spring5;public class User {private int id;private String name;public User() {}public User(int id, String name) {this.id = id;this.name = name;}//    public void setId(int id) {//        this.id = id;
//    }
//
//    public void setName(String name) {//        this.name = name;
//    }@Overridepublic String toString() {return "User{" +"id=" + id +", name='" + name + '\'' +'}';}public void add(){System.out.println("add......");}
}
<?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="user" class="com.jackma.spring5.User"><constructor-arg name="id" value="2"></constructor-arg><constructor-arg name="name" value="马保国"></constructor-arg></bean></beans>

测试代码同上,结果:

基于XML方式注入其他类型的属性

注入null

使用set方法注入为上面的name属性注入null,那么就要修改xml文件(注意User类要提供set方法):

    <bean id="user" class="com.jackma.spring5.User"><property name="id" value="3"></property><property name="name"><null></null> // 就是这个</property></bean>

测试代码同上,结果:

注入特殊符号

使用set方法注入为上面的name属性注入含有特殊符号<>的数据,那么就要修改xml文件,使用<![CDATA[...内容...]]>,这样它就会将内容之间输出:

<!--    属性值包含特殊符号--><bean id="user" class="com.jackma.spring5.User"><property name="id" value="3"></property><property name="name"><value><![CDATA[<马云>]]></value> // 就是这个</property></bean>

测试代码同上,结果:

注入引用数据类型

看一个案例:有一个公司Company,有一个部门类Dept和一个员工类Emp,Emp中有一个Dept类型的属性,用来表示员工的部门:
    Dept:

package com.jackma.spring5.company;
// 部门类
public class Dept {private String dname;public void setDname(String dname) {this.dname = dname;}@Overridepublic String toString() {return "Dept{" +"dname='" + dname + '\'' +'}';}
}

Emp:

package com.jackma.spring5.company;// 员工类
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;}public Dept getDept() {return dept;}@Overridepublic String toString() {return "Emp{" +"ename='" + ename + '\'' +", gender='" + gender + '\'' +", dept=" + dept +'}';}
}

使用外部bean

xml中添加外部bean:

<!--    外部bean--><bean id="emp" class="com.jackma.spring5.company.Emp"><property name="ename" value="马云"></property><property name="gender" value="男"></property><property name="dept" ref="dept" ></property></bean>// 外部bean<bean name="dept" class="com.jackma.spring5.company.Dept"><property name="dname" value="退休了"></property></bean>

测试:

@Testpublic void test3(){// 测试内部beanApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");Emp emp = context.getBean("emp", Emp.class);System.out.println(emp);}

使用内部bean

xml中添加内部bean:

<!--    内部bean--><bean id="emp" class="com.jackma.spring5.company.Emp"><property name="ename" value="马云"></property><property name="gender" value="男"></property><property name="dept" >// 内部bean<bean name="dept" class="com.jackma.spring5.company.Dept"><property name="dname" value="总裁"></property></bean></property></bean>

测试代码同上,结果:

级联赋值

先关联(外部bean或者内部bean),后赋值:先使用外部bean关联,然后赋值为首席执行官

<bean id="emp" class="com.jackma.spring5.company.Emp"><property name="ename" value="马云"></property><property name="gender" value="男"></property><property name="dept" ref="dept"></property><property name="dept.dname" value="首席执行官"></property></bean><bean name="dept" class="com.jackma.spring5.company.Dept"><property name="dname" value="总裁"></property></bean>

测试代码同上,结果:

注入集合类型

注入集合类型包括:数组、List、Set、Map。使用Stu类来演示:
    第一步是添加属性,并提供对应set方法:

package com.jackma.spring5.collectiontype;import java.util.List;
import java.util.Map;
import java.util.Set;public class Stu{private String[] course;private List<String> list;private Set<String> set;private Map<String, String> maps;public void setCourse(String[] course) {this.course = course;}public void setList(List<String> list) {this.list = list;}public void setSet(Set<String> set) {this.set = set;}public void setMaps(Map<String, String> maps) {this.maps = maps;}public void test(){// 测试类System.out.println(Arrays.toString(course));System.out.println(list);System.out.println(set);System.out.println(maps);}
}

第二步是在Spring配置文件中配置bean:

<?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="stu" class="com.jackma.spring5.collectiontype.Stu">
<!--    数组类型属性注入--><property name="course"><array><value>JavaSE</value><value>JavaWeb</value><value>JavaEE</value></array></property><!--    数组类型属性注入--><property name="list"><list><value>语文</value><value>数学</value><value>英语</value></list></property><!--    Set类型属性注入--><property name="set"><set><value>早上</value><value>中午</value><value>晚上</value></set></property><!--    Map类型属性注入--><property name="maps"><map><entry key="蒙牛" value="酸酸乳"></entry><entry key="瓜子" value="二手车"></entry><entry key="O泡" value="时间到"></entry></map></property>
</bean>
</beans>

测试:

设置集合属性对象类型的值

先创建一个类Course表示一个学生学的课程

package com.jackma.spring5.collectiontype;public class Course {private String name;public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "Course{" +"name='" + name + '\'' +'}';}
}

然后Stu类中添加一个存放Course类型数据的属性List,然后提供set方法:

// 学生所学的多门课程private List<Course> list2;public void setList2(List<Course> list2) {this.list2 = list2;// 用来测试public void test1(){System.out.println(list2);}
}

现在我们要对List中Course类型的对象进行赋值,xml文件配置:

<!--    设置集合属性对象类型的值--><bean id="stu" class="com.jackma.spring5.collectiontype.Stu"><property name="list2"><list><ref bean="course1" ></ref><ref bean="course2" ></ref></list></property></bean><bean id="course1" class="com.jackma.spring5.collectiontype.Course"><property name="name" value="物理"></property></bean><bean id="course2" class="com.jackma.spring5.collectiontype.Course"><property name="name" value="化学"></property></bean>

测试:

@Testpublic void test5(){// 测试设置集合属性对象类型的值ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");Stu stu = context.getBean("stu", Stu.class);stu.test1();}

提取集合类型属性的注入部分

先写一个book类:

package com.jackma.spring5.collectiontype;import java.util.List;
import java.util.Set;public class Book {private List<String> book;private List<String> book2;public void setBook(List<String> book) {this.book = book;}public void setBook2(List<String> book2) {this.book2 = book2;}public void test(){System.out.println("bean1" + book);}public void test2(){System.out.println("bean2:" + book2);}}

步骤:

  1. 在Spring配置文件中引入名称空间util:
<?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:util="http://www.springframework.org/schema/util"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/utilhttp://www.springframework.org/schema/util/spring-util.xsd">
</beans>
  1. 使用util标签完成提取list集合类型属性的提取(相当于是一个公共的,可以注入到多个List类型的bean中),下面把提取出来的booklist注入到list和list2两个bean中:
<?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:util="http://www.springframework.org/schema/util"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/utilhttp://www.springframework.org/schema/util/spring-util.xsd"><util:list id="booklist"><value>语文</value><value>数学</value><value>英语</value></util:list><bean id="list" class="com.jackma.spring5.collectiontype.Book"><property name="book" ref="booklist"></property></bean><bean id="list2" class="com.jackma.spring5.collectiontype.Book"><property name="book2" ref="booklist"></property></bean>
</beans>

测试:

@Testpublic void test5(){// 测试设置集合属性对象类型的值ApplicationContext context = new ClassPathXmlApplicationContext("bean3.xml");Book book = context.getBean("list:", Book.class);book.test();Book book2 = context.getBean("list2", Book.class);book2.test2();}

普通bean和工厂bean

什么是普通 bean?前面我们在配置文件中定义的bean就是普通bean,其创建的类型就是返回类型:

而工厂 bean就是在配置文件中定义bean的类型可以和返回类型不一样,下面来举个例子:

  1. 先新建一个包factorybean,然后在包里新建一个类Mybean:
package com.jackma.spring5.factorybean;public class Mybean {}

改之前先看一下使用普通bean的结果会是什么样子,创建xml文件(注意这里写的类型是Mybean):

<?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="myBean" class="com.jackma.spring5.factorybean.Mybean"></bean>
</beans>

测试和结果:

@Testpublic void test6(){// 测试工厂beanApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml");Mybean mybean = context.getBean("myBean", Mybean.class);System.out.println(mybean);}


    可以看到这里是一个Mybean类型的,接下来把它改成Coursr类型的。

  1. 让这个类作为工厂bean,实现接口FactoryBean,并实现 接口里面的方法,在实现的方法中定义返回的bean类型:
package com.jackma.spring5.factorybean;import com.jackma.spring5.collectiontype.Course;
import org.springframework.beans.factory.FactoryBean;public class Mybean implements FactoryBean<Course> {// 定义返回bean的类型@Overridepublic Course getObject() throws Exception {Course course = new Course();course.setName("newbean");return course;}@Overridepublic Class<?> getObjectType() {return null;}@Overridepublic boolean isSingleton() {return false;}
}

修改测试代码:

@Testpublic void test6(){// 测试工厂beanApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml");Course course = context.getBean("myBean", Course.class);System.out.println(course);}

bean的作用域

  1. 在Spring里,我们可以设置bean是单实例还是多实例。
  2. 默认为单实例。
    拿前面那个Book类来测试:
// 测试单实例多实例ApplicationContext context = new ClassPathXmlApplicationContext("bean3.xml");Book book1 = context.getBean("list", Book.class);Book book2 = context.getBean("list", Book.class);System.out.print("book1 == book2 ?     ");System.out.println(book1 == book2);System.out.println(book1);System.out.println(book2);


    可以看到两个book的地址相同,就说明是单实例,那么如何改成多实例?bean 标签里面有属性scope来实现:

    可以看到有两个值,其中singleton表示是单实例对象,是默认值;而prototype表示是多实例对象。那么修改后结果就变成:

    注意事项:设置scope值是 singleton时候,加载spring配置文件时候就会创建单实例对象。 设置scope值是prototype时候,不是在加载spring配置文件时候创建对象,而是在调用getBean方法时候创建多实例对象。

bean的生命周期

什么是生命周期?就是从对象创建到对象销毁的过程,bean的生命周期如下:

  1. 通过构造器创建bean实例(无参数构造)
  2. 为bean的属性设置值和对其他bean引用(调用 set 方法)
  3. 调用bean的初始化的方法(需要进行配置初始化的方法)
  4. 获取到了创建的bean实例对象(对象获取到了)
  5. 当容器关闭时候,调用bean的销毁的方法(需要进行配置销毁的方法)

创建一个Orders类来演示bean的生命周期:

package com.jackma.spring5.bean;public class Orders {private String oname;public Orders() {System.out.println("第一步,执行了无参构造函数,创建实例");}public void setOname(String oname) {this.oname = oname;System.out.println("第二步,set注入属性");}public void initMethod(){System.out.println("第三步,调用bean的初始化的方法");}public void destroyMethod(){System.out.println("第五步,销毁bean");}
}

需要在配置文件中配置bean的初始化的方法和bean的销毁的方法init-method和destroy-method:

<?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="orders" class="com.jackma.spring5.bean.Orders" init-method="initMethod" destroy-method="destroyMethod"><property name="oname" value="手机"></property>
</bean>
</beans>

bean的销毁的方法还需要自行调用:

@Testpublic void test7(){// 测试生命周期ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean5.xml");Orders orders = context.getBean("orders", Orders.class);System.out.println("第四步,获取到了创建的bean实例对象:");System.out.println(orders);// 手动让bean实例销毁context.close();}

以上是bean基本的生命周期,总共有5步,但如果添加了bean的后置处理器之后,还会有两个步骤,即生命周期变成7步:

  1. 通过构造器创建bean实例(无参数构造)
  2. 为bean的属性设置值和对其他bean引用(调用 set 方法)
  3. 把bean实例传递bean后置处理器的方法postProcessBeforeInitialization
  4. 调用bean的初始化的方法(需要进行配置初始化的方法)
  5. bean实例传递bean后置处理器的方法postProcessAfterInitialization
  6. 获取到了创建的bean实例对象(对象获取到了)
  7. 当容器关闭时候,调用bean的销毁的方法(需要进行配置销毁的方法)

怎么添加bean的后置处理器?首先要创建一个类来实现BeanPostProcessor接口:

package com.jackma.spring5.bean;import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;public class MyBeanPost implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println("在初始化之前执行的方法");return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("在初始化之后执行的方法");return bean;}
}

然后在配置文件中配置后置处理器:

<?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="orders" class="com.jackma.spring5.bean.Orders" init-method="initMethod" destroy-method="destroyMethod"><property name="oname" value="手机"></property>
</bean>
<!--    配置后置处理器--><bean id="mybeanpost" class="com.jackma.spring5.bean.MyBeanPost"></bean>
</beans>

测试代码同上,结果:

XML的自动装配

什么是自动装配?根据指定装配规则(属性名称或者属性类型),Spring 自动将匹配的属性值进行注入。举例:

  1. 创建一个包autowire,创建一个Emp类和一个Dept类:

Emp:

package com.jackma.spring5.autowire;public class Emp{private Dept dept;public void setDept(Dept dept) {this.dept = dept;}@Overridepublic String toString() {return "Emp{" +"dept=" + dept +'}';}public void test(){System.out.println(this);}
}

Dept:

package com.jackma.spring5.autowire;// 部门类
public class Dept {@Overridepublic String toString() {return "Dept{}";}
}
  1. 没设置自动装载前的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="emp" class="com.jackma.spring5.autowire.Emp"><property name="dept" ref="dept"></property>
</bean><bean id="dept" class="com.jackma.spring5.autowire.Dept"></bean>
</beans>

测试和结果:

@Testpublic void test8(){// 测试自动装载ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean6.xml");Emp emp = context.getBean("emp", Emp.class);emp.test();}


    下面来配置自动装载,配置文件中的bean标签有一个属性autowire,可以用来配置自动装配:

    autowire 属性常用两个值:byName根据属性名称注入 ,注入值bean的id值和类属性名称一样;byType根据属性类型注入(如果使用byType,那么相同类型的bean不能定义多个,不然就不知道是哪一个了):

<!--    配置自动装配--><bean id="emp" class="com.jackma.spring5.autowire.Emp" autowire="byName"></bean><bean id="dept" class="com.jackma.spring5.autowire.Dept"></bean>
<!--    配置自动装配--><bean id="emp" class="com.jackma.spring5.autowire.Emp" autowire="byType"></bean><bean id="dept" class="com.jackma.spring5.autowire.Dept"></bean>

测试和结果:

外部属性文件

应用场景:假设要创建一个数据库的连接池,按照以往的方法创建,假如我们的用户名或者密码之类的信息要修改,那么同时就要对xml文件中的bean进行修改:

<?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="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<!--        直接配置--><property name="driverClassName" value="com,mysql.jdbc.Driver"></property>--><property name="url" value="jdbc.mysql://localhost:3306/userDb"></property>--><property name="username" value="root"></property>--><property name="password" value="123456"></property>--></bean>
</beans>

改进方法是创建一个properties外部属性文件,然后把信息注入到xml文件中,这样在修改信息时只需要修改properties文件即可:
    首先提供properties文件:

    然后需要在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.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd">
<!--配置德鲁伊数据库连接池-->
<!--        引入外部属性文件--><context:property-placeholder location="classpath:jdbc.properties"/>
<!--        配置连接池--><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><!-- 获取properties文件内容,根据key获取,使用spring表达式获取 --><property name="driverClassName" value="${prop.driverClass}"></property><property name="url" value="${prop.url}"></property><property name="username" value="${prop.userName}"></property><property name="password" value="${prop.passWord}"></property></bean>
</beans>

基于注解方式创建对象

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

  1. @Component
  2. @Service
  3. @Controller
  4. @Repository

注解方式创建对象的步骤:

  1. 引入AOP依赖。
  2. 开启组件扫描:扫描类中的注解,需要用到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.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd">
<!--开启组件扫描--><context:component-scan base-package="com.jackma.spring5.service"></context:component-scan>
</beans>
  1. 新建一个类,在类上面添加创建对象注解
package com.jackma.spring5.service;import org.springframework.stereotype.Component;// 注解里的value相当于bean里的id值,也可以不写,若不写则默认为首字母小写的类名
@Component(value = "userService") // <bean id="userService">
public class UserService {public void add(){System.out.println("Service add......");}
}

测试和结果:

@Testpublic void test9(){// 测试自动装载ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean8.xml");UserService userservice = context.getBean("userService", UserService.class);userservice.add();}


    开启组件扫描时默认扫描包中所有的类,但也可以进行配置,使得它扫描指定的类:

<context:component-scan base-package="com.jackma.spring5.service" use-default-filters="false"><context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/><context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/></context:component-scan>

context标签中有属性use-default-filters,true表示使用默认的扫描,而false表示不使用默认的扫描,然后在下面自己设置扫描的方法:
    context:include-filter:设置扫描哪些内容;context:exclude-filter:设置哪些内容不进行扫描,type表示根据什么来扫描,这里我设置成按照注解来扫描,然后expression选择注解的类型,我在这是扫描注解类型是Component的,不扫描Controller类型的。
    此外,type的类型还有:

基于注解方式注入属性

和上面的创建对象一样,Spring针对Bean管理中注入属性提供的注解有:

  1. @Autowired:根据属性类型进行自动装配
  2. @Qualifier:根据名称进行注入
  3. @Resource:可以根据类型注入,可以根据名称注入
  4. @Value:注入普通类型属性

实例:有一个ManService类,一个ManDaoImpl类实现ManDAO接口和它里面的upDate()方法,现在要在ManService类中调用这个方法:
    步骤:

  1. 在Man类和ManDaoImpl类添加创建对象的注解
  2. 在service中注入dao对象,在service类添加dao类型属性,在属性上面使用注解,不用提供set方法

@Autowired

ManDao 接口:

package com.jackma.spring.dao;public interface ManDao {public void upDate();
}

接口实现类ManDaoImpl :

package com.jackma.spring.dao;import org.springframework.stereotype.Repository;@Repository(value = "manDaoImpl")
public class ManDaoImpl implements ManDao {@Overridepublic void upDate() {System.out.println("dao upDate......");}
}

ManService :

package com.jackma.spring;import com.jackma.spring.dao.ManDao;
import com.jackma.spring.dao.ManDaoImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;@Repository(value = "manService")
public class ManService {// 定义DAO类型属性,添加注入属性注解// 不用提供set方法@Autowired // 根据类型注入ManDao manDao = new ManDaoImpl();public void add(){System.out.println("service add......");manDao.upDate();}
}

测试:

@Testpublic void test10(){// 测试注解注入属性ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean8.xml");ManService manService = context.getBean("manService", ManService.class);manService.add();}

@Qualifier

这个@Qualifier 注解的使用,和上面@Autowired 一起使用。因为万一ManDao有多个实现类,而仅仅使用@Autowired的话它不知道是哪个实现类,因此可以使用@Qualifier来指定特定名字的实现类。

package com.jackma.spring;import com.jackma.spring.dao.ManDao;
import com.jackma.spring.dao.ManDaoImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Repository;@Repository(value = "manService")
public class ManService {// 定义DAO类型属性,添加注入属性注解// 不用提供set方法@Autowired // 根据类型注入@Qualifier(value = "manDaoImpl")ManDao manDao = new ManDaoImpl();public void add(){System.out.println("service add......");manDao.upDate();}
}

@Resource

结合了上两个注解的效果:

package com.jackma.spring;import com.jackma.spring.dao.ManDao;
import com.jackma.spring.dao.ManDaoImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Repository;import javax.annotation.Resource;@Repository(value = "manService")
public class ManService {// 定义DAO类型属性,添加注入属性注解// 不用提供set方法
//    @Autowired // 根据类型注入
//    @Qualifier(value = "userDaoImpl")
//    @Resource // 根据类型注入@Resource(name = "manDaoImpl") // 根据名称注入ManDao manDao = new ManDaoImpl();public void add(){System.out.println("service add......");manDao.upDate();}
}

@Value

注入普通类型属性:

package com.jackma.spring;import com.jackma.spring.dao.ManDao;
import com.jackma.spring.dao.ManDaoImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Repository;import javax.annotation.Resource;@Repository(value = "manService")
public class ManService {// 定义DAO类型属性,添加注入属性注解// 不用提供set方法
//    @Autowired // 根据类型注入
//    @Qualifier(value = "userDaoImpl")
//    @Resource // 根据类型注入@Resource(name = "manDaoImpl") // 根据名称注入ManDao manDao = new ManDaoImpl();@Value("马保国")private String name;public void add(){System.out.println("service add......");manDao.upDate();System.out.println("name:" + name);}
}

测试代码相同:

完全注解开发

完全注解开发,即使用一个配置类来替代 xml 配置文件。
    创建配置类,替代 xml 配置文件:

package com.jackma.spring;import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;@Configuration
@ComponentScan(basePackages = "com.jackma.spring")
public class SpringConfig {}

测试:

@Testpublic void test11(){// 测试纯注解开发// 加载配置类ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);ManService man = context.getBean(ManService.class);man.add();}

Java之Spring5:IOC容器相关推荐

  1. [Spring5]IOC容器_底层原理

    IOC的概念和原理 什么是IOC 1.控制反转,把对象创建和对象之间的调用过程,交给Spring进行管理 2.使用IOC目的:为了耦合度减低 IOC底层原理 xml解析 工厂模式 反射 底层原理示例图 ...

  2. [Spring5]IOC容器_Bean管理_bean的作用域和bean的生命周期

    IOC操作Bean管理(bean作用域) 1.在Spring里面,设置创建bean实例是单实例还是多实例 2.在Spring里面,默认情况下,bean是单实例对象 package com.atguig ...

  3. [Spring5]IOC容器_Bean管理XML方式_注入集合类型属性

    xml注入集合属性 1.注入数组类型属性 2.注入List集合类型属性 3.注入Map集合类型属性 (1)创建类,定义数组,list,map,set类型属性,生成对应set方法 package com ...

  4. [Spring5]IOC容器_Bean管理注解方式_创建对象

    IOC操心Bean管理(基于注解方式) 1.什么是注解 (1)注解是代码特殊标记,格式:@注解名称(属性名称=属性值,属性名称=属性值-) (2)使用注解,注解作用在类上面,方法上面,属性上面 (3) ...

  5. [Spring5]IOC容器_Bean管理XML方式_外部属性文件

    IOC操作Bean管理(外部属性文件) 1.直接配置数据库信息 (1)配置德鲁伊druid连接池 (2)引入德鲁伊druid连接池依赖jar包 <!--直接配置连接池--><bean ...

  6. [Spring5]IOC容器_Bean管理XML方式_自动装配

    IOC操作Bean管理(xml自动装配) package com.atguigu.spring.autowire;public class Dept {@Overridepublic String t ...

  7. [Spring5]IOC容器_Bean管理_工厂Bean

    IOC操作Bean管理(FactoryBean) 1.Spring有两种类型bean,一种普通bean,另外一种工厂bean(FactoryBean) 2.普通bean:在配置文件中定义bean类型就 ...

  8. [Spring5]IOC容器_Bean管理XML方式_创建对象_set注入属性and有参构造注入属性

    IOC操作 Bean管理 什么是Bean管理 1.Bean管理指的是两个操作: a.Spring创建对象 b.Spring注入属性 2.Bean管理操作有两种方式 a.基于xml配置文件方式实现 b. ...

  9. [Spring5]IOC容器_Bean管理注解方式_完全注解开发

    完全注解开发 (1)创建配置类,替代xml配置文件 package com.atguigu.spring.config;import org.springframework.context.annot ...

最新文章

  1. JQuery 实现遮罩层
  2. android 文字路径,Android自定义控件:路径及文字
  3. dqn在训练过程中loss越来越大_DQN算法实现注意事项及排错方法
  4. 崛起吧,亲爱的,该背单词了!!!
  5. 电路常识性概念(1)-输入、输出阻抗
  6. 如何用Pygame写游戏(六)
  7. WIN7 系统破解LoadRunner 11
  8. 推荐系统系列教程之十一:那些在Netflix Prize中大放异彩的推荐算法
  9. Android视频桌面,动态桌面开发
  10. Axure软件的简单使用
  11. 打开Word提示向程序发送命令时出现问题怎么办?
  12. 硬件设计基础----MOS管
  13. 【NOI科目校 信息学知识点测评-组合计数专题】展览方案
  14. VS+Opencv出现:xxx处有未经处理的异常: Microsoft C++ 异常: cv::Exception,位于内存位置xxx处。
  15. php elasticsearch更新文档
  16. C语言高一,高一数学上学期的所有知识点
  17. Android 如何获取应用签名
  18. 投资理财-言微不劝人
  19. QT 调用 百度翻译API 写的在线翻译程序
  20. stm32mp157和imx6ull比较,开发板选哪个好?一文看懂!

热门文章

  1. Android项目分包(按功能模块)
  2. 计算机网络的三网的概念,“三网融合”的含义是什么
  3. Monde Nissin向菲律宾证券交易委员会提交首次公开发行注册申请
  4. 初中计算机试题戏曲进校园,【校园通讯】“戏曲进校园”走进东街学校,春风化新雨,戏曲百媚生!...
  5. OpenWRT刷固件
  6. 什么是SSD固态硬盘的QLC、SLC、MLC、TLC
  7. 如何理解EDG夺冠后的疯狂?
  8. 使用iText生成PDF文件中创建表格
  9. python 3.8.2(32-bit)安装教程_Python 3.8.2详细图文安装教程(附安装包)
  10. CAN诊断的寻址方式