Spring IOC
Spring简介
Spring是一个IOC和AOP的容器框架,可以管理所有的组件
Spring的优良特性:
- 非侵入式,基于Spring开发的应用中的对象可以不依赖于Spring的API
- 依赖注入,IOC
- 面向切面编程,AOP
- 容器,Spring是一个容器,它管理应用对象的生命周期
- 组件化,使用简单的组件配置组合复杂的应用
- 一站式,在IOC和AOP的基础上可以整合各种优秀的第三方库
Spring的模块划分
Test:Spring的单元测试模块
Core Container:核心容器(IOC);黑色代表这部分功能由哪些JAR包组成
AOP+Aspects:面向切面编程
Data Access/Integration:数据访问/集成
Web:Spring开发web应用
IOC(Inversion Of Control)控制反转、DI
控制:资源的获取方式
获取资源的方式
主动式:需要什么资源都自己创建即可
BookServlet{
BookService bs = new BookService() ;
AirPlane ap = new AirPlane(很多参数);//复杂对象的创建偶尔度很高
}
被动式:资源的获取是交给一个容器来创建和设置,将实现与具体进行分离
BookServlet{
BookService bs;
public void test01(){
bs.checkout();
}
}
容器:管理所有的组件的生命周期
DI(Dependency Injection)依赖注入:组件A运行时需要另一个组件B,容器通过反射的方式将准备好的B注入到A中
HelloWorld
-
添加依赖与环境搭建
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.2.RELEASE</version> </dependency>
public class Person {
private String lastName;
private Integer age ;
private String gender;
private String email ;
}
-
配置
<?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"> <!--注册一个person对象 Spring会自动创建这个对象--> <!--一个bean标签可以注册一个组件 class 要注册组件的全类名 id 这个对象的唯一标识 使用property标签为Person对象的属性赋值 name指定属性名 value指定对应属性的值 --> <bean id="person01" class="cn.jason.bean.Person"> <property name="lastName" value="Harry"/> <property name="age" value="16"/> <property name="email" value="aaa@qq.com"/> <property name="gender" value="女"/> </bean> </beans>
-
测试
public void test01(){
//ApplicationContext(IOC容器的接口)代表IOC容器
//ClassPathXmlApplicationContext 使用当前配置文件构造IOC容器
ApplicationContext ioc = new ClassPathXmlApplicationContext("ioc.xml");
System.out.println("容器启动完成...");
Person person01 = (Person)ioc.getBean("person01");
Person person02 = (Person)ioc.getBean("person01");
System.out.println(person01);
System.out.println(person01 == person02);
}
person构建完成...
容器启动完成...
Person{lastName='Harry', age=16, gender='女', email='aaa@qq.com'}
true
几个细节
-
组件的创建工作是容器完成的
-
容器中对象的创建在容器构建完成的时候就被实例化
-
同一个组件在IOC容器中是单实例的
-
容器中如果没有这个组件,获取会报异常
-
IOC容器在创建这个组件对象的时候,会利用setter方法为javaBean赋值
-
javaBean的属性名是由是由getter和setter方法决定的;去掉get/set后面那一串首字母小写就是属性名
public void setLastName(String lastName) //属性名就是lastName
实验
实验一,根据bean的类型从ioc容器中获取bean实例
/*
根据bean的类型从ioc容器中获取bean实例
如果ioc容器中这个类型的bean由多个,查找会报错
*/
public void test02(){
Person bean = ioc.getBean(Person.class);
System.out.println(bean);
}
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'cn.jason.bean.Person' available: expected single matching bean but found 2: person01,person02
或者传入指定的id和bean类型
public void test02(){
Person bean = ioc.getBean("person01",Person.class);
System.out.println(bean);
}
实验二,使用有参构造器创建对象
public class Person {
private String lastName;
private Integer age ;
private String gender;
private String email ;
public Person(){
System.out.println("person无参构建完成...");
}
public Person(String lastName, Integer age, String gender, String email) {
this.lastName = lastName;
this.age = age;
this.gender = gender;
this.email = email;
System.out.println("person有参构建完成...");
}
}
<?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="person03" class="cn.jason.bean.Person">
<!--调用有参构造器来创建对象-->
<constructor-arg name="lastName" value="Jason"/>
<constructor-arg name="age" value="20"/>
<constructor-arg name="email" value="aaa@qq.com"/>
<constructor-arg name="gender" value="男"/>
</bean>
</beans>
public void test(){
Person person = ioc.getBean("person03",Person.class) ;
System.out.println(person);
}
person有参构建完成...
Person{lastName='Jason', age=20, gender='男', email='aaa@qq.com'}
使用p名称空间为bean赋值
<!--
导入名称空间
xmlns:p="http://www.springframework.org/schema/p"
-->
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"
>
<bean id="person04" class="cn.jason.bean.Person" p:lastName="Mio" p:age="18" p:email="aaa@qq.com" p:gender="女"/>
</beans>
实验四、为不同类型的属性赋值
用到的实体类
public class Person {
//基本类型直接使用property标签自动进行类型转换赋值
private String lastName;
private Integer age ;
private String gender;
private String email ;
private Car car ;
private List<Book> books ;
private Map<String,Object> map ;
private Properties properties ;
}
public class Car {
private String name;
private Integer price ;
private String color ;
}
public class Book {
private String name ;
private String author ;
}
**赋值为null null标签 **
<?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="person01" class="cn.jason.bean.Person">
<property name="lastName">
<!--在property标签体内进行复杂的赋值-->
<null/>
</property>
</bean>
<!-- 错误的做法 -->
<bean id="person01" class="cn.jason.bean.Person">
<!-- 这样是为lastName赋值为“null”的字符串 -->
<property name="lastName" value="null">
</property>
</bean>
</beans>
为person对象的car属性赋值
第一种
<bean id="car01" class="cn.jason.bean.Car">
<property name="color" value="red"/>
<property name="name" value="BMW"/>
<property name="price" value="1000000"/>
</bean>
<bean id="person01" class="cn.jason.bean.Person">
<!--ref 代表引用外面的一个值 car = ioc.getBean("car01")-->
<property name="car" ref="car01"/>
</bean>
public void test(){
Person person = ioc.getBean("person01",Person.class);
System.out.println(person.getCar());
System.out.println(person.getCar() == ioc.getBean("car01",Car.class));
}
Car{name='BMW', price=1000000, color='red'}
true
第二种
<?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="person01" class="cn.jason.bean.Person">
<property name="car">
<!--
在properties标签体内进行复杂的赋值
对象可以使用bean标签创建,既car = new Car();-->
<bean class="cn.jason.bean.Car" >
<property name="name" value="自行车"/>
<property name="color" value="green"/>
<property name="price" value="12313123"/>
</bean>
</property>
</bean>
</beans>
public void test(){
Person person = ioc.getBean("person01",Person.class);
System.out.println(person.getCar());
System.out.println(person.getCar() == ioc.getBean("car01",Car.class));
}
Car{name='自行车', price=12313123, color='green'}
false
为List赋值 list标签
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="book01" class="cn.jason.bean.Book">
<property name="name" value="东游记"/>
</bean>
<bean id="person" class="cn.jason.bean.Person">
<!--为list类型赋值-->
<property name="books">
<!--books = new ArrayList<Book>();-->
<list>
<!--内部bean不能被获取到,只能在内部使用-->
<bean class="cn.jason.bean.Book" p:name="西游记"/>
<!--引用外部一个元素-->
<ref bean="book01"/>
</list>
</property>
</bean>
</beans>
为map赋值 map标签
<bean class="cn.jason.bean.Book" id="book" p:name="西游记"/>
<bean id="person" class="cn.jason.bean.Person">
<property name="map">
<!--map = new LinkedHashMap();-->
<map>
<!--一个entry代表一个key value-->
<entry key="name" value="Mioaaa"/>
<entry key="key02" value="23333"/>
<entry key="book" value-ref="book"/>
<entry key="mapInner">
<bean id="car" class="cn.jason.bean.Car" p:name="BMW"/>
</entry>
<entry key="mapInner">
<map>
<entry key="22" value="33"/>
<entry key="33" value="22"/>
</map>
</entry>
</map>
</property>
</bean>
public void test(){
Person person = ioc.getBean("person", Person.class);
Map<String, Object> map = person.getMap();
System.out.println(map);
}
{name=Mioaaa, key02=23333, book=Book{name='西游记', author='null'}, mapInner={22=33, 33=22}}
为properties赋值 props标签
<bean id="person" class="cn.jason.bean.Person">
<!--properties = new Properties();所有k=v都是string-->
<property name="properties">
<props>
<prop key="key01">value01</prop>
<prop key="key02">value02</prop>
</props>
</property>
</bean>
util名称空间创建集合类型的bean
xmlns:util="http://www.springframework.org/schema/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:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<bean id="person" class="cn.jason.bean.Person">
<property name="map" ref="myMap"/>
<property name="books" ref="myList"/>
</bean>
<!--相当于new LinkedHashMap();-->
<util:map id="myMap">
<entry key="key01" value="value01"></entry>
<entry key="key02" value="value02"></entry>
</util:map>
<util:list id="myList">
<bean id="book" class="cn.jason.bean.Book">
<property name="name" value="西游记"/>
</bean>
<bean id="book" class="cn.jason.bean.Book">
<property name="name" value="东游记"/>
</bean>
</util:list>
</beans>
public void test(){
Person person = ioc.getBean("person", Person.class);
Map<String, Object> map = person.getMap();
List<Book> books = person.getBooks();
System.out.println(books);
System.out.println(map);
}
[Book{name='西游记', author='null'}, Book{name='东游记', author='null'}]
{key01=value01, key02=value02}
为级联属性赋值
<bean id="car01" class="cn.jason.bean.Car" p:name="BMW" p:color="Red"/>
<bean id="person01" class="cn.jason.bean.Person">
<property name="car" ref="car01"/>
<property name="car.name" value="自行车"/>
</bean>
public void test(){
Person person = ioc.getBean("person01", Person.class);
Car car = person.getCar();
System.out.println(car);
}
//结果 Car{name='自行车', color='Red'}
通过parent属性实现配置信息的重用
<!-- abstract="true" 表示这个bean的配置是一个抽象的模板,不能获取它的实例,只能给别人继承 -->
<bean id="person01" class="cn.jason.bean.Person" abstract="true">
<property name="lastName" value="Mio"/>
<property name="age" value="18"/>
<property name="gender" value="男"/>
<property name="email" value="aaa@qq.com"/>
</bean>
<!--parent 指定当前bean配置信息继承于哪个bean,把person01的信息继承到person02中-->
<bean id="person02" parent="person01">
<!-- 将需要修改的数据重新指定 -->
<property name="lastName" value="Harry"/>
</bean>
改变bean之间的创建顺序
<!-- 改变bean的创建顺序-->
<!-- bean之间的依赖(只是 改变创建顺序)-->
<!-- 这里表示这个car对象依赖于book和person这两个对象 -->
<!-- 先创建person和book再创建car-->
<bean class="cn.jason.bean.Car" id="car" depends-on="person,book"></bean>
<bean class="cn.jason.bean.Book" id="book"></bean>
<bean id="person" class="cn.jason.bean.Person" ></bean>
bean的作用域,分别创建单实例和多实例bean
<!--
bean的作用域:指bean是单实例还是多实例,默认情况下是单实例的
prototype:多实例的
容器启动默认不会去创建多实例的bean
当要使用的时候才创建它
每次获取都会创建一个新的实例对象
singleton:单实例的(默认的)
单实例的在容器启动完成之前就已经创建好对象,保存在容器中
任何时候获取都是获取之前创建好的bean
-->
<bean class="cn.jason.bean.Book" id="book01" scope="prototype" p:name="BMW"></bean>
<bean class="cn.jason.bean.Book" id="book02" scope="singleton" p:name="BMW"></bean>
通过自定义工厂去创建bean对象
<!--
工厂模式:工厂帮我们创建对象,创建对象的复杂工作交给工厂,对创建bean的细节进行隐藏
ioc容器在启动时,通过这个静态工厂来构建book对象,并且把它添加到容器中保存(单例)
静态工厂
class:指定静态工厂的全类名
factory-method指定工厂方法
constructor-arg:可以为方法传递参数
返回类型的是该工厂方法返回的类型,也就是Book
static Book getBook(String name)
-->
<bean id="book" class="cn.jason.factory.StaticFactory" factory-method="getBook">
<constructor-arg name="name" value="碧蓝航线"/>
</bean>
</beans>
<!-- 实例工厂
先实例化工厂
-->
<bean id="instanceFactory" class="cn.jason.factory.InstanceFactory"/>
<!-- factory-bean:指定使用哪个工厂对象来创建这个bean对象
factory-method:指定使用该工厂的哪个方法来创建对象
-->
<bean id="book" class="cn.jason.bean.Book" factory-bean="instanceFactory"
factory-method="getBook">
<constructor-arg name="name" value="碧蓝航线"/>
</bean>
FactoryBean接口
<!-- FactoryBean(是Spring规定的一个接口) 只要是这个接口的实现类,Spring都认为是一个工厂
实现该接口的工厂在ioc容器启动时不会创建bean对象,只有当使用时才会实例化对象
-->
<bean id="book" class="cn.jason.factory.MyFactoryBean"></bean>
/*
* 实现了FactoryBean接口的类是Spring可以认识的工厂类
* Spring会自动的调用工厂方法创建对象的实例
* getObject就是工厂方法
* */
public class MyFactoryBean implements FactoryBean<Book> {
//返回创建的对象
public Book getObject() throws Exception {
System.out.println("MyFactoryBean创建对象中");
Book book = new Book() ;
book.setName(UUID.randomUUID().toString());
return book;
}
// Spring通过这个方法来确认创建对象的类型
public Class<?> getObjectType() {
return Book.class ;
}
// 所创建的对象是否是单例的
public boolean isSingleton() {
return true;
}
}
bean的生命周期方法
public class Book {
private String name;
private String author ;
public void init(){
System.out.println("初始化...");
}
public void destory(){
System.out.println("销毁...");
}
}
public class IOCTest {
ConfigurableApplicationContext ioc = new
ClassPathXmlApplicationContext("ApplicationContext.xml") ;
@Test
public void test(){
ioc.close();
}
}
<!--
创建带有生命周期方法的bean
生命周期:bean的创建到销毁的过程
ioc容器中注册的bean
单例的bean,容器启动时创建好,容器关闭也会销毁创建的bean
多实例bean,获取的时候才创建
为bean指定一些生命周期方法,Spring在创建或者是销毁的时候会调用这些方法
-->
<bean class="cn.jason.bean.Book" id="book1" destroy-method="destory" init-method="init"/>
orgaaa@qq.com6956de9: startup
book 被创建
初始化...
org.springframework.context.support.AbstractApplicationContext doClose
销毁...
bean的后置处理器
<bean class="cn.jason.bean.Book" id="book1" destroy-method="destory" init-method="init" scope="singleton"/>
<!-- bean的后置处理器
Spring有一个接口BeanPostProcessor(后置处理器),可以在bean的初始化前后调用这个方法
无论这个bean是否有初始化方法,后置处理器都会工作
-->
<bean id="myBeanPostProcessor" class="cn.jason.bean.MyBeanPostProcessor"></bean>
/**
* 1、编写后置处理器的实现类
* 2、将后置处理器注册到配置文件中
*/
public class MyBeanPostProcessor implements BeanPostProcessor {
// 在bean初始化前执行
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println(beanName+"要准备调用初始化方法啦");
return bean;
}
// 在bean初始化后执行
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println(beanName+"初始化结束");
//初始化之后返回的bean,返回的是什么,容器中保存的就是什么
return bean;
}
}
public class IOCTest {
ConfigurableApplicationContext ioc = new ClassPathXmlApplicationContext("ApplicationContext.xml") ;
@Test
public void test(){
Book book1 = ioc.getBean("book1", Book.class);
book1 = new Book() ;
}
}
输出:
book 被创建
book1要准备调用初始化方法啦
初始化...
book1初始化结束
book 被创建
使用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.xsd">
<!-- 使用context名称空间加载外部配置文件
固定写法classpath,表示引用类路径下的一个资源
使用${}取值
-->
<context:property-placeholder location="classpath:Druid.properties"/>
<bean class="cn.jason.bean.Data" id="data">
<property name="map">
<map>
<entry key="url" value="${url}"/>
<entry key="username" value="${username}"/>
<entry key="password" value="${password}"/>
<entry key="initialSize" value="${initialSize}"/>
<entry key="maxActive" value="${maxActive}"/>
<entry key="maxWait" value="${maxWait}"/>
</map>
</property>
</bean>
</beans>
基于XML的自动装配(自定义类型自动赋值)
Spring在创建bean对象时,自动的为某些属性赋值
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
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.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<!-- 为person里面的自定义类型的属性赋值
properties 手动赋值
自动赋值(自动装配)
自动装配
autowire="default"和 autowire="no" 不自动装配
按照某种规则自动装配
autowire="byName"以属性名作为id去容器中找到某个组件,将该组件赋值给它
例如public void setCar(Car car) 属性名为car,那么就在xml文件中找id为car的组件,将该组件赋值给它
autowire="byType"以属性的类型作为class去容器中找到某个组件,将该组件赋值给它,若找到多个会报错
autowire="constructor"按照构造器进行赋值
它是先按照构造器参数的类型进行匹配,找不到就为null;如果按照类型查找到了多个相同类型的则通过参数名作为id进行匹配,找不到就为null
-->
<bean id="car" class="cn.jason.bean.Car" p:name="碧蓝航线" p:price="1000"/>
<bean id="book" class="cn.jason.bean.Book" p:name="blhx" p:price="1000"/>
<bean id="person" class="cn.jason.bean.Person" autowire="byName"/>
</beans>
public class Person {
private Book book ;
private Car car ;
public Book getBook() {
return book;
}
public void setBook(Book book) {
this.book = book;
}
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
@Override
public String toString() {
return "Person{" +
"book=" + book +
", car=" + car +
'}';
}
}
public class MyTest {
ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
@Test
public void test(){
Person bean = ioc.getBean(Person.class);
System.out.println(bean);
}
}
Person{book=Book{name='blhx', price=1000.0}, car=Car{name='碧蓝航线', price=1000}}
SpEL (Spring Expression Language)
<bean class="cn.jason.bean.Car" id="car">
<property name="name" value="BMW"/>
</bean>
<bean class="cn.jason.bean.Book" id="book" >
<property name="name" value="asdasd"/>
</bean>
<bean id="person" class="cn.jason.bean.Person">
<!-- 使用运算符 -->
<property name="salary" value="#{232.123*12}"/>
<!-- 引用其他bean的某个属性值 -->
<property name="lastName" value="#{book.name}"/>
<property name="car" value="#{car}"/>
<!-- 调用静态方法 语法规则: #{T(静态类全类名).静态方法(参数列表)}-->
<property name="email" value="#{T(java.util.UUID).randomUUID().toString().substring(0,5)}"/>
<!-- 调用实例方法 语法规则:#{对象.方法} -->
<property name="gender" value="#{book.getName()}"/>
</bean>
public void test(){
Person person = ioc.getBean("person", Person.class);
System.out.println(person);
}
//结果Person{lastName='asdasd', email='4fb85', gender='asdasd', age=null, salary=2785.4759999999997, car=Car{name='BMW', color='null'}, books=null, map=null}
通过给bean上添加注解,可以快速的将bean添加到ioc容器中
<?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.xsd">
<!-- 通过注解,将bean添加到IOC容器中
Spring 有四个注解,某个类上添加上任何一个注解都能将这个组件加入到ioc容器中
@Controller 控制器,推荐给控制器层组件添加这个注解
@Service 业务逻辑,推荐给业务逻辑层添加这个注解
@Repository 持久化层,推荐给持久化层添加这个注解
@Component 组件,给不属于以上几层的组件添加这个注解
使用注解将组件添加到容器中需要几步:
1、给要添加的组件上标准这四个注解中的任何一个
2、告诉Spring扫描加了注解的组件(依赖Context名称空间)
3、导入aop包,支持注解模式
使用注解的方式和使用配置的方式行为默认是一样的
1、组件id,默认是类名首字母小写
2、组件的作用域,默认是单例的
-->
<!-- context:component-scan 自动组件扫描
base-package:指定扫描的基础包,把基础包以及他下面所有的包的所有加了注解的bean,自动的扫描进IOC容器
-->
<context:component-scan base-package="cn.jason"/>
</beans>
/**
* id为bookDao
* 作用域为多实例
*/
@Repository("bookDao")
@Scope(value = "prototype")
public class BookDao {
}
使用context:include-filter 指定扫描包时要包含的类
<!-- context:include-filter 指定只扫描哪些组件
type="annotation" 只扫描加了该注解的组件
use-default-filters="false
禁用默认过滤规则(默认行为是全部扫描进来的),和include有冲突
-->
<context:component-scan base-package="cn.jason" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
</context:component-scan>
使用context:exclude-filter 指定扫描包时不要包含的类
<!-- context:exclude-filter扫描过程中排除一些不要的组件
type:指定排除规则
type="annotation" 按照注解进行排除,标注了指定注解的组件不要
expression 指定值,这里指定注解的全类名
type="assignable" 指定排除某个具体类
expression 指定要排除的全类名
type="aspectj" aspectj表达式
type="custom" 自定义一个TypeFilter,自定义使用哪些
type="regex" 正则表达式
-->
<context:component-scan base-package="cn.jason">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>
使用@Autowired 注解实现根据类型实现自动装配
<?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.xsd">
<!--
扫描指定包,将加了注解的组件加入IOC容器中
-->
<context:component-scan base-package="cn.jason">
</context:component-scan>
</beans>
@Repository("bookDao")
@Scope(value = "prototype")
public class BookDao {
public void saveBook(){
System.out.println("保存了一本图书");
}
}
@Service
public class BookService {
//required = false 表示找不到就装配null
@Autowired(required = false)
private BookDao bookDao;
public void save(){
System.out.println("bookDao正在保存图书");
bookDao.saveBook();
}
}
@Controller
public class BookServlet {
//自动装配(自动为这个属性赋值)
//required = false 表示找不到就装配null
@Autowired(required = false)
private BookService bookService ;
public void doGet(){
bookService.save();
}
}
public class IOCTest {
ConfigurableApplicationContext ioc = new ClassPathXmlApplicationContext("ApplicationContext.xml") ;
@Test
public void test(){
BookServlet bookServlet = ioc.getBean("bookServlet", BookServlet.class);
bookServlet.doGet();
}
}
//结果bookDao
//正在保存图书
//保存了一本图书
@Autowired原理
@Autowired
private BookService bookService ;
- 先按照类型去容器中找到对应的组件;bookService = ioc.getBean(BookService .class) ;
1、如果找到一个直接赋值
2、如果没找到就抛出异常
3、如果找到多个,则按照变量名作为id继续在容器中进行匹配
a、如果没有匹配上就报错
b、如果匹配上就进行装配
也可以使用**@Qualifier**注解指定一个值,让Spring在查找时使用这个注解指定的值和容器中组件的id进行匹配,而不是通过变量名
现在添加一个类BookServiceExt
@Service
public class BookServiceExt extends BookService {
@Override
public void save() {
System.out.println("BookServiceExt...");
bookDao.saveBook();
}
}
//修改BookServlet类
@Controller
public class BookServlet {
//自动装配(自动为这个属性赋值)
//required = false 表示找不到就装配null
@Autowired(required = false)
private BookService bookServiceExt ;
public void doGet(){
bookServiceExt.save();
}
}
//结果
//BookServiceExt...
//保存了一本图书
@Controller
public class BookServlet {
@Qualifier("bookService")
//自动装配(自动为这个属性赋值)
@Autowired(required = false)
private BookService hahaha ;
public void doGet(){
hahaha.save();
}
}
//结果
//BookService...
//保存了一本图书
在方法上使用@Autowired注解和在方法的参数上使用@Qualifier注解
@Service
public class BookService {
// required = false 表示找不到返回null,而不是报错
// 在方法上使用Autowired的话,这个参数需要的自定义类型会自动装入
// 并且这个方法会在创建bean时会自动调用
@Autowired(required = false)
// @Qualifier("bookDao")指示将id为bookDao的bean注入过来
public void method(@Qualifier("bookDao") BookDao dao){
dao.saveBook();
}
}
public class IOCTest {
ConfigurableApplicationContext ioc = new ClassPathXmlApplicationContext("ApplicationContext.xml") ;
@Test
public void test(){
}
}
//结果
//保存了一本图书
@Autowired与@Resource的区别
@Autowired、@Resource都是自动装配
@Autowired 功能强大,是Spring的注解
@Resource是Java的标准,扩展性更强,可以切换成任意的容器,而@Autowired就不行
泛型的依赖注入
public abstract class BaseDao<T> {
public abstract void save();
}
@Repository("bookDao")
@Scope(value = "singleton")
public class BookDao extends BaseDao<Book> {
public void save() {
System.out.println("保存了一本图书");
}
}
@Repository
@Scope(value = "singleton")
public class UserDao extends BaseDao<User> {
public void save() {
System.out.println("保存用户信息");
}
}
public abstract class BaseService<T> {
@Autowired
BaseDao<T> baseDao ;
public void save(){
System.out.println("自动注入的dao" + baseDao);
baseDao.save();
}
}
@Service
public class BookService extends BaseService<Book> {}
@Service
public class UserService extends BaseService<User> {}
public class IOCTest {
ConfigurableApplicationContext ioc = new ClassPathXmlApplicationContext("ApplicationContext.xml") ;
@Test
public void test(){
BookService bookService = ioc.getBean(BookService.class);
UserService userService = ioc.getBean(UserService.class);
bookService.save();
userService.save();
}
}
/*输出
自动注入的aaa@qq.com
保存了一本图书
自动注入的aaa@qq.com
保存用户信息
*/
/*
BaseDao<T>定义了基本的CRUD
BookDao和UserDao为具体实现,并且将他们加入ioc容器中
BaseService<T> 中聚合了一个BaseDao<T>
BookService和UserService为具体实现,并且将他们加入ioc容器中
在test方法中分别调用了BookService和UserService的save方法,都显示出正确的结果
问题:ioc容器如何为BookService和UserService中的BaseDao<T> 正确的注入依赖呢
BookService 继承至 BaseService<Book> ,也就是聚合了BaseDao<Book> ,ioc容器为其注入依赖时先通过类型查找容器中是否有该bean ,既查找是否有BaseDao<Book>类型的bean,由于BookDao继承至BaseDao<Book>,所以就匹配到了BookDao;UserService同理
*/
上一篇: Junit4在SSM中应用
下一篇: C++之STL常用算法