目录

1. 依赖注入的三种方式

                 1.2  构造器注入

                 1.3 使用setter注入

                 1.4 接口注入

2. bean的装配

                 2.1  简易值装配

                 2.2 集合装配

                 2.3  命名空间装配

                 2.4  通过注解装配


1. 依赖注入的三种方式

  • 构造器注入
  • setter注入
  • 接口注入

1.2  构造器注入

在Spring中创建bean的时候必须提供一个无参构造器,否则Spring将抛出异常,程序报错,为什么呢?因为Spring容器在创建bean的时候会先创建一个空壳,即Bean里面的元素全为null的对象,然后会在后面再将配置的属性进行填充,这样可以防止循环注入,Spring的构造器注入方式如下配置,即可使用

<bean id="person" class="com.xxx.Person" ></bean>

但是如果使用有参数构造器,可以不用提供无参构造器,就要在配置文件里进行配置以构造器模式创建对象,但是不推荐这种方式。因为可读性差,如果属性多了,还得注意构造器的index值,容易出错

<bean id="person" class="com.xxx.blog.Person">
		<constructor-arg index="0" value="516" />
		<constructor-arg index="1" value="20" />
	</bean>

 

1.3 使用setter注入

使用setter注入当然就得提供setter方法了,然后在配置文件里使用<property>标签配置,Spring容器会通过反射调用setter方法填充属性值,setter方式必须提供一个无参构造器,否则Spring将无法创建对象

<bean id="person" class="com.xxx.blog.Person">
        <property name="name" value="516"/>
        <property name="age" value="18"/>
    </bean>

 

1.4 接口注入

   暂时留着 2019.01.08  21:16

 

 


2. bean的装配

 

2.1  简易值装配

像八种数据类型和他的包装类以及String可以直接在value里面写入值

<bean id="person" class="com.xxx.blog.Person">
        <property name="name" value="516"/>
        <property name="age" value="18"/>
        <!-- 引用类型装配 -->
        <property name="book" ref="math"/>
    </bean>

    <bean id="math" class="com.xxx.blog.Math"></bean>

 

2.2 集合装配

2.2.1 Map类型

其中name就是属性名称了,然后往里面存入一些值

<property name="studentScore">
    <map>
        <entry key="stu2" value="60"></entry>
        <entry key="stu3" value="50"></entry>
        <entry key="stu1" value="65"></entry>
        <entry key="stu1" value="65"></entry>
        <!--引用类型装配 -->
        <entry key-ref="stu4" value-ref="class4"></entry>
    </map>
</property>

<bean id="stu4" class="com.xxx.blog.Stu4"></bean>
<bean id="class4" class="com.xxx.blog.Class4"></bean>

2.2.2 Set类型

<property name="NamesSet">
    <set>
        <value>Tom</value>
        <value>G.E.M</value>
        <value>Lisa</value>
        <!--引用类型装配 -->
        <ref bean="role1" />
    </set>
</property>

<bean id="role1" class="com.xxx.blog.Role1"></bean>

2.2.3 List类型

<property name="girlList">
    <list>
        <value>吴宣仪</value>
        <value>邓紫棋</value>
        <value>宋茜</value>
         <!--引用类型装配 -->
        <ref bean="gir4" />
    </list>
</property>

<bean id="gir4" class="com.xxx.blog.Gir4"></bean>

2.2.4数组类型

<property name="array">  
	<array>              
		<value>5</value> 
		<value>1</value> 
		<value>6</value> 
        <!--引用类型装配 -->
        <ref bean="num" />
	</array>             
</property>          

<bean id="num" class="com.xxx.blog.Num"></bean>

 

2.3  命名空间装配

命名空间装配需要引入Spring的命名空间

xmlns:c="http://www.springframework.org/schema/c"
    xmlns:p="http://www.springframework.org/schema/p"

c 代表是Constructor(构造器)的意思,所以示例使用构造器方式

public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
<bean id="person" class="com.xxx.blog.Person" c:name="517" c:age="18"></bean>

p就是property 对应着上面<property>标签的意思,使用setter方式注入值,所以必须提供setter方法和无参构造器

<bean id="person" class="com.xxx.blog.Person" p:name="520" p:age="18"></bean>
private String name;
    private Integer age;
    /**setter/无参构造器 **/

 

2.4  通过注解装配

 使用注解可以减少xml的繁琐配置,但并不意味着可以代替xml方式,所以要根据业务逻辑选择合适的方式

 

2.4.1 @Component

在类上加入@Component注解可以使当前类被Spring容器管理,成为一个bean,@Component注解里面的value属性代表当前bean的id名称, 如果不写默认就为当前类名小写(person)

package com.xxx.blog;

@Component(value="per")
public class Person{
	
	@Value("516")
	private String name;
	@Value("11")
	private Integer age;
	
	/**setter/getter **/
}

当前只是定义了一个bean,但要是想要被Spring管理还得让Spring知道去哪里找这些bean,@ComponentScan对应着Xml配置文件里面的    <context:component-scan base-package="com.xxx.blog" /> 意思都是通知Spring去哪里扫描bean,而@ComponentScan注解如果不写范围,默认值就是当前类所在的包和子包

package com.xxx.blog;

@ComponentScan
public class Config {

}

----------------------------------------------
package com.xxx.study;

@ComponentScan(basePackages= {"com.xxx.blog","com.xxx.test"})
public class Config {

}

这时候测试就需要用AnnotationConfigApplicationContext类去初始化SpringIoc容器

ApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
 Object bean = context.getBean("person");                                                        
 System.out.println(bean);

 

2.4.2 @Autowired

@Autowired可以根据类型自动装配,@Value只能注入基本数据类型和他的包装类,但@Autowired就可以注入另一个Bean

@Component
public class HomeWork {
	
	@Value("English")
	private String name;
	@Value("90")
	private String score;
	
}

@Component
public class Student {

	@Autowired
	private HomeWork homeWork;
	
}

首先就是注入一个普通HomeWorkBean,然后在管理Student时发现@Autowired HomeWork ,这时候就会去IOC容器寻找是否有HomeWork.class的bean,如果找到就注入,否则抛出异常,如果不想抛出异常就这样配置@Autowired(required=false),意思就是这个bean找不到也没有关系,不是必须的,

 

2.4.3 @Primary

在使用@Autowired的时候也可以使用接口类型注入,如下

spring构造方法自动注入 spring 构造注入_Spring

此时有一个JavaTeacher实现了Teacher接口,最终IOC容器会将实现类JavaTeacher注入到teacher字段

@Component
public class JavaTeacher implements Teacher{

	@Override
	public String toString() {
		return "JavaTeacher";
	}
	
}

Spring推荐面向接口开发,所以难免会有一个接口有多个实现类,那么此时再这样子写就会报错,因为Spring不知道该注入哪一个,所以有两个注解@Primary,@Qualifier帮助我们解决这种情况,当存在多个实现类的时候我们可以使用@Primary来指定一个bean为优先注入的

@Component
public class JavaTeacher implements Teacher{

	@Override
	public String toString() {
		return "JavaTeacher";
	}	
}
-----------------------------------------------
@Primary
@Component
public class KotlinTeacher implements Teacher{
	
	@Override
	public String toString() {
		return "KotlinTeacher";
	}
}

即以上两个bean都实现了teacher接口,则如果出现冲突,则会使用@Primary修饰的bean注入

 

2.4.4 @Qualifier

@Qualifier也是解决多个实现类冲突的,其value值就是bean的id,所以就是根据id来注入,@Component修饰的bean默认id是类名小写,然后结果最终是注入了JavaTeacher

@Autowired
@Qualifier("javaTeacher")
private Teacher teacher;

 

2.4.5 @Bean

@Component注解只能在类上使用,而如果我们想用注解把第三方的类成为一个Bean,就需要@Bean注解了

在使用@Bean注解的时候,一定要加一个@Conifguration 否则Spring无法扫描到当前类,@Configuration代表当前类为一个配置类,@Bean修饰的方法最终的返回值就是一个Bean,然后被Spring容器管理,value属性存储的是当前bean的id

@Configuration
public class TestBean {
	
	@Bean(value="dataSource")
	public DataSource getDataSource() {
		DataSource dataSource = new DataSource();
		dataSource.setDriverName("com.jdbc.mysql.Driver");
		dataSource.setUrl("jdbc:mysql:///spring");
		dataSource.setUsername("root");
		dataSource.setPassword("sx516");
		return dataSource;
	}
}

@Bean还有其他属性 比如自定义初始化方法和销毁方法 ,在原Bean里添加与配置的方法名一样的方法后就会被Spring容器调用

@Bean(value="dataSource",initMethod="init",destroyMethod="destroy")
public void init() {
    System.out.println("啊 我活了");
}
	
public void destroy() {
    System.out.println("啊 我死了");
}

spring构造方法自动注入 spring 构造注入_Spring学习_02

 

2.4.5 @Conditional

根据条件判断是否生成bean

首先新建一个类并实现Condition接口,重写的方法的返回值决定着是否创建bean,context可以获取到Spring运行时环境Environment,然后判断是否包含属性“name”,包含就创建这个bean

import org.springframework.context.annotation.Condition;
public class ConditionalTest implements Condition{

	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		Environment environment = context.getEnvironment();
		return environment.containsProperty("name");
	}
}

在getBean方法上有一个@Conditional注解里面的参数就是对应的条件类,如果返回true就创建这个bean 

@Configuration
@ComponentScan
@PropertySource(value= {"classpath:student.properties"})
public class Config {
	
	@Value("${name}")
	private String name;
	
	@Value("${age}")
	private String age;
	
	@Value("${level}")
	private String level;
	
	@Bean(name="my")
	@Conditional({ConditionalTest.class})
	public My getBean() {
		return new My(name,age,level);
	}
}