Java之Spring5:IOC容器
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);}}
步骤:
- 在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>
- 使用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的类型可以和返回类型不一样,下面来举个例子:
- 先新建一个包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类型的。
- 让这个类作为工厂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的作用域
- 在Spring里,我们可以设置bean是单实例还是多实例。
- 默认为单实例。
拿前面那个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的生命周期如下:
- 通过构造器创建bean实例(无参数构造)
- 为bean的属性设置值和对其他bean引用(调用 set 方法)
- 调用bean的初始化的方法(需要进行配置初始化的方法)
- 获取到了创建的bean实例对象(对象获取到了)
- 当容器关闭时候,调用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步:
- 通过构造器创建bean实例(无参数构造)
- 为bean的属性设置值和对其他bean引用(调用 set 方法)
- 把bean实例传递bean后置处理器的方法postProcessBeforeInitialization
- 调用bean的初始化的方法(需要进行配置初始化的方法)
- bean实例传递bean后置处理器的方法postProcessAfterInitialization
- 获取到了创建的bean实例对象(对象获取到了)
- 当容器关闭时候,调用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 自动将匹配的属性值进行注入。举例:
- 创建一个包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{}";}
}
- 没设置自动装载前的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管理中创建对象提供的注解:
- @Component
- @Service
- @Controller
- @Repository
注解方式创建对象的步骤:
- 引入AOP依赖。
- 开启组件扫描:扫描类中的注解,需要用到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>
- 新建一个类,在类上面添加创建对象注解
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管理中注入属性提供的注解有:
- @Autowired:根据属性类型进行自动装配
- @Qualifier:根据名称进行注入
- @Resource:可以根据类型注入,可以根据名称注入
- @Value:注入普通类型属性
实例:有一个ManService类,一个ManDaoImpl类实现ManDAO接口和它里面的upDate()方法,现在要在ManService类中调用这个方法:
步骤:
- 在Man类和ManDaoImpl类添加创建对象的注解
- 在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容器相关推荐
- [Spring5]IOC容器_底层原理
IOC的概念和原理 什么是IOC 1.控制反转,把对象创建和对象之间的调用过程,交给Spring进行管理 2.使用IOC目的:为了耦合度减低 IOC底层原理 xml解析 工厂模式 反射 底层原理示例图 ...
- [Spring5]IOC容器_Bean管理_bean的作用域和bean的生命周期
IOC操作Bean管理(bean作用域) 1.在Spring里面,设置创建bean实例是单实例还是多实例 2.在Spring里面,默认情况下,bean是单实例对象 package com.atguig ...
- [Spring5]IOC容器_Bean管理XML方式_注入集合类型属性
xml注入集合属性 1.注入数组类型属性 2.注入List集合类型属性 3.注入Map集合类型属性 (1)创建类,定义数组,list,map,set类型属性,生成对应set方法 package com ...
- [Spring5]IOC容器_Bean管理注解方式_创建对象
IOC操心Bean管理(基于注解方式) 1.什么是注解 (1)注解是代码特殊标记,格式:@注解名称(属性名称=属性值,属性名称=属性值-) (2)使用注解,注解作用在类上面,方法上面,属性上面 (3) ...
- [Spring5]IOC容器_Bean管理XML方式_外部属性文件
IOC操作Bean管理(外部属性文件) 1.直接配置数据库信息 (1)配置德鲁伊druid连接池 (2)引入德鲁伊druid连接池依赖jar包 <!--直接配置连接池--><bean ...
- [Spring5]IOC容器_Bean管理XML方式_自动装配
IOC操作Bean管理(xml自动装配) package com.atguigu.spring.autowire;public class Dept {@Overridepublic String t ...
- [Spring5]IOC容器_Bean管理_工厂Bean
IOC操作Bean管理(FactoryBean) 1.Spring有两种类型bean,一种普通bean,另外一种工厂bean(FactoryBean) 2.普通bean:在配置文件中定义bean类型就 ...
- [Spring5]IOC容器_Bean管理XML方式_创建对象_set注入属性and有参构造注入属性
IOC操作 Bean管理 什么是Bean管理 1.Bean管理指的是两个操作: a.Spring创建对象 b.Spring注入属性 2.Bean管理操作有两种方式 a.基于xml配置文件方式实现 b. ...
- [Spring5]IOC容器_Bean管理注解方式_完全注解开发
完全注解开发 (1)创建配置类,替代xml配置文件 package com.atguigu.spring.config;import org.springframework.context.annot ...
最新文章
- JQuery 实现遮罩层
- android 文字路径,Android自定义控件:路径及文字
- dqn在训练过程中loss越来越大_DQN算法实现注意事项及排错方法
- 崛起吧,亲爱的,该背单词了!!!
- 电路常识性概念(1)-输入、输出阻抗
- 如何用Pygame写游戏(六)
- WIN7 系统破解LoadRunner 11
- 推荐系统系列教程之十一:那些在Netflix Prize中大放异彩的推荐算法
- Android视频桌面,动态桌面开发
- Axure软件的简单使用
- 打开Word提示向程序发送命令时出现问题怎么办?
- 硬件设计基础----MOS管
- 【NOI科目校 信息学知识点测评-组合计数专题】展览方案
- VS+Opencv出现:xxx处有未经处理的异常: Microsoft C++ 异常: cv::Exception,位于内存位置xxx处。
- php elasticsearch更新文档
- C语言高一,高一数学上学期的所有知识点
- Android 如何获取应用签名
- 投资理财-言微不劝人
- QT 调用 百度翻译API 写的在线翻译程序
- stm32mp157和imx6ull比较,开发板选哪个好?一文看懂!
热门文章
- Android项目分包(按功能模块)
- 计算机网络的三网的概念,“三网融合”的含义是什么
- Monde Nissin向菲律宾证券交易委员会提交首次公开发行注册申请
- 初中计算机试题戏曲进校园,【校园通讯】“戏曲进校园”走进东街学校,春风化新雨,戏曲百媚生!...
- OpenWRT刷固件
- 什么是SSD固态硬盘的QLC、SLC、MLC、TLC
- 如何理解EDG夺冠后的疯狂?
- 使用iText生成PDF文件中创建表格
- python 3.8.2(32-bit)安装教程_Python 3.8.2详细图文安装教程(附安装包)
- CAN诊断的寻址方式