谈起Spring ,大家都听过 控制反转 依赖注入。到底什么叫控制反转,什么叫依赖注入呢。
控制反转(IOC):就是传统的方式中,我们会通过 new关键字去创建对象,由程序主动是进行对象的创建,控制对象的生命周期。控制反转就是将对象的控制权交出给 IOC容器,不在主动去创建对象,由IOC容器去创建对象,控制对象的生命周期。
依赖注入(DI):当A需要引用B对象时,在传统方式中,我们会在A中new 一个B对象,然后使用它。而依赖注入能动态的向某个对象提供它需要的对象。例如A需要B,但是A不需要创建B对象,只需要将需求告诉Spring容器,A无需知道B是怎么创建的,什么时候创建。当程序运行时,spring会在合适的时候创建一个B对象,然后像打针一样注射给A,这样A就可以依赖B对象而运行了。而DI的真正实现是依赖于反射。反射允许程序在运行的时候动态的生成对象、执行对象的方法、改变对象的属性,spring就是通过反射来实现注入的。
Bean的装配:基于java的显示配置,基于xml的显示配置,隐式bean扫描和自动装配。
一、隐式bean扫描和自动装配
实现自动化装配 是通过组件扫描和自动装配 组合实现的。
创建类时,在类上加上@Conponent 注解,就是告诉Spring要为这个类创建bean。Spring会自动识别该注解。
例如:
package com.tzw.common;
import org.springframework.stereotype.Component;
@Component
public class GuzTrans {
}
当然这个需要spring扫描扫描到才能创建。所以我们需要显式配置spring的自动扫描。配置有两种方式,基于xml的配置和基于javaConfig的配置。
除了@Component注解外,还有其他的注解亦可以实现spring扫描
@Conponent 用于让Spring扫描识别,一般用于不确定的什么层的类上。
@Service ,是@Component的扩展,一般用于注解到Service层的类上。
@Controller,是@Component的扩展,一般用于web层的实现。控制层上。
@Repository,是@Component的扩展,一般用于注解到Dao层的类上。
(1)基于xml的配置。需要<context:component-scan>,而base-package则是指定要扫描的包,包括该包和该包的子包。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.tzw"></context:component-scan>
</beans>
(2)基于javaConfig配置
package com.tzw.common;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
@Configuration
@ComponentScan(basePackages = "com.tzw")
public class GuzConfig {
}
这里提到了@Configuration注解,接下来javaConfig显示装配就会用到。
(3)自动装配。以上实现了自动扫描的隐式配置,接下来要进行自动装配,说白了就是bean于bean之间的依赖关系。
实现自动装配的需要一些注解。@Autowired用来实现注入。
例如
package com.tzw.common;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class GuzService {
@Autowired
public GuzDao guzDao;
public void getClientList(){
guzDao.getClient();
}
}
package com.tzw.common;
import org.springframework.stereotype.Repository;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Repository
public class GuzDao {
public List<Map<String,Object>> getClient(){
return new ArrayList<Map<String,Object>>();
}
}
这样就实现将 GuzDao 注入到GuzService。实现了自动装配。
@Autowired ,是spring自带的注解,是根据类型注入的。如果想用名称注入,需要搭配@qualifier。此外,还有一个required属性,用法:@Autowired(required=false),表示为如果找不到这个bean,不会抛出异常。反之,抛出异常。
@Inject,JSR330规范实现的,根据类型注入。如果想用名称注入,需要搭配@Named。
@Resource,JSR250规范实现的,按照名称匹配的。
所以使用它们需要导入不同的包。
二、javaConfig显示配置
这里不得不提到两个注解@Configuration 和 @Bean
@Configuration 表明该类是配置类。@Bean会告诉Spring这个方法将会返回一个对象。
package com.tzw.javaConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class JavaConfig {
@Bean
public Client getClient(){
return new Client();
}
}
javaConfig方式实现注入
两种方式:1.属性注入 2.构造方法注入;
1.setter注入,通过set方式注入。
package com.tzw.javaConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class JavaConfig {
@Bean
public Client getClient(){
Client client = new Client();
client.setIdent(ident());
return client;
}
@Bean
public Ident ident(){
return new Ident();
}
}
package com.tzw.javaConfig;
public class Client {
public String clientName;
public Ident ident;
public String getClientName() {
return clientName;
}
public void setClientName(String clientName) {
this.clientName = clientName;
}
public Ident getIdent() {
return ident;
}
public void setIdent(Ident ident) {
this.ident = ident;
}
@Override
public String toString() {
return "Client{" +
"clientName='" + clientName + '\'' +
", ident=" + ident +
'}';
}
}
2.构造器注入。通过构造方式注入。
package com.tzw.javaConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class JavaConfig {
@Bean
public Client getClient(){
Client client = new Client(ident());
return client;
}
@Bean
public Ident ident(){
return new Ident();
}
}
package com.tzw.javaConfig;
public class Client {
public String clientName;
public Ident ident;
public Client(Ident ident){
this.ident=ident;
}
public String getClientName() {
return clientName;
}
public void setClientName(String clientName) {
this.clientName = clientName;
}
public Ident getIdent() {
return ident;
}
public void setIdent(Ident ident) {
this.ident = ident;
}
@Override
public String toString() {
return "Client{" +
"clientName='" + clientName + '\'' +
", ident=" + ident +
'}';
}
}
三、xml配置实现注入
1.setter方式注入,利用properties属性注入
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.tzw"></context:component-scan>
<bean id="ident" class="com.tzw.javaConfig.Ident"></bean>
<!--setter方式注入-->
<bean id="client" class="com.tzw.javaConfig.Client">
<property name="ident" ref="ident"></property>
</bean>
</beans>
2.构造方法注入,利用<constructor-arg>注入
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.tzw"></context:component-scan>
<bean id="ident" class="com.tzw.javaConfig.Ident"></bean>
<!--setter方式注入-->
<!--bean id="client" class="com.tzw.javaConfig.Client">
<property name="ident" ref="ident"></property>
</bean>-->
<!--构造器注入-->
<bean id="client" class="com.tzw.javaConfig.Client">
<constructor-arg ref="ident"></constructor-arg>
</bean>
</beans>
四、混合注入
混合注入四种方式:
1.xml配置插入xml配置,利用<import>标签
2.xml配置插入javaConfig配置,xml中通过配置<bean>,将javaConfig配置引入xml文件中
3.java配置插入java配置,通过@Import 注解引入。
4.java配置插入xml配置,通过@ImportResource注解引入。
1.xml 引用xml。 一个xml中bean 注入另一个xml的bean
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.tzw"></context:component-scan>
<!--<bean id="ident" class="com.tzw.javaConfig.Ident"></bean>-->
<!--setter方式注入-->
<!--bean id="client" class="com.tzw.javaConfig.Client">
<property name="ident" ref="ident"></property>
</bean>-->
<import resource="spring1.xml"/>
<!--构造器注入-->
<bean id="client" class="com.tzw.javaConfig.Client">
<constructor-arg ref="ident"></constructor-arg>
</bean>
</beans>
2.xml引用java配置,一个javaConfig的bean 注入xml中的bean
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.tzw"></context:component-scan>
<!--<bean id="ident" class="com.tzw.javaConfig.Ident"></bean>-->
<!--setter方式注入-->
<!--bean id="client" class="com.tzw.javaConfig.Client">
<property name="ident" ref="ident"></property>
</bean>-->
<bean class="com.tzw.javaConfig.IdentConfig"></bean>
<!--构造器注入-->
<bean id="client" class="com.tzw.javaConfig.Client">
<constructor-arg ref="ident"></constructor-arg>
</bean>
</beans>
package com.tzw.javaConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class IdentConfig {
@Bean
public Ident ident(){
return new Ident();
}
}
3.java引用java,一个javaConfig的bean注入另一个JavaConfig的bean
package com.tzw.javaConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
@Import(IdentConfig.class)
public class JavaConfig {
@Bean
public Client getClient(Ident ident){
Client client = new Client(ident);
return client;
}
}
package com.tzw.javaConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class IdentConfig {
@Bean
public Ident ident(){
return new Ident();
}
}
4.java引用xml,通过@ImportResouce引入。不能把 xml申明的bean注入到javaConfig中
同时引用xml的配置和Java的配置。
package com.tzw.javaConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportResource;
@Configuration
@ImportResource("spring1.xml")
@Import(Ident.class)
public class JavaConfig {
@Bean
public Client getClient(Ident ident){
Client client = new Client(ident);
return client;
}
}
这样,xml中的bean和JavaConfig中的bean都会启动。但是javaConfig中的bean不能注入xml中的bean。这中方式 xml的配置和javaConfig的配置都是完整的,不能像上面那种方式混合使用。
五、虽然javaConfig和xml配置都可以使用,但是如果要注入的是集合,javaConfig配置就无法满足,就只能用xml配置实现。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.tzw"></context:component-scan>
<bean id="ident" class="com.tzw.javaConfig.Ident">
<property name="idNo" value="1"></property>
<property name="idType" value="2"></property>
<property name="idList">
<list>
<value>123456</value>
<value>987654</value>
</list>
</property>
<property name="idMap">
<map>
<entry key="1" value="张三"></entry>
<entry key="2" value="李四"></entry>
</map>
</property>
</bean>
</beans>