Spring总结 1.装配bean

时间:2021-12-01 08:36:53

本随笔内容要点如下:

  • 依赖注入
  • Spring装配bean的方式
  • 条件化装配

一、依赖注入

  我理解的依赖注入是这样的:所谓的依赖,就是对象所依赖的其他对象。Spring提供了一个bean容器,它负责创建应用程序中的bean并通过依赖注入来协调这些对象之间的关系,实现自动创建与管理所创建的对象。我们只需要通过配置来命令Spring提供的容器来完成bean的装配。

二、Spring装配bean的方式

  在Spring中,装配bean有三种方式:

  1. 通过xml进行配置
  2. 通过Java进行配置
  3. 通过注解来自动扫描并配置

  先使用xml进行举例:

 package cn.powerfully.domain;

 public class ABean {
private String str;
private double num; public ABean() {
} public ABean(String str, double num) {
this.str = str;
this.num = num;
} public String getStr() {
return str;
} public void setStr(String str) {
this.str = str;
} public double getNum() {
return num;
} public void setNum(double num) {
this.num = num;
}
}

在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="aBean" class="cn.powerfully.domain.ABean">
<constructor-arg name="str" value="bean"/>
<constructor-arg name="num" value="3.1415926"/>
</bean> </beans>

   使用bean标签来表示装载一个bean到Spring容器,默认该bean为单例,即容器中只有一个该类对象。对于字段的注入,上面使用了构造器注入,Spring还支持setter注入,通过<property>标签进行注入,具体的可以参考帮助文档。为了简化,spring提供了c命名空间和p命名空间,用来简化构造器注入和setter注入,上面的例子可以改编成如下:

<?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:c="http://www.springframework.org/schema/c"
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="aBean" class="cn.powerfully.domain.ABean" p:str="p namespace" p:num="3.14" /> -->
<bean id="aBean" class="cn.powerfully.domain.ABean" c:str="c namespace" c:num="3.14" /> </beans>

  其他基本类型和上面的例子一样,直接编写即可。对于注入对象与集合,将有所不同:

 package cn.powerfully.domain;

 import java.util.List;
import java.util.Map;
import java.util.Properties; public class BBean { private ABean aBean;
private List<String> list;
private Map<String, Integer> map;
private Properties props; public ABean getaBean() {
return aBean;
} public void setaBean(ABean aBean) {
this.aBean = aBean;
} public List<String> getList() {
return list;
} public void setList(List<String> list) {
this.list = list;
} public Map<String, Integer> getMap() {
return map;
} public void setMap(Map<String, Integer> map) {
this.map = map;
} public Properties getProps() {
return props;
} public void setProps(Properties props) {
this.props = props;
} }

  实例化该类时,需要注入对象、List、Map、Properties,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"
xmlns:c="http://www.springframework.org/schema/c"
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="aBean" class="cn.powerfully.domain.ABean" p:str="p namespace" p:num="3.14" /> -->
<bean id="aBean" class="cn.powerfully.domain.ABean" c:str="c namespace" c:num="3.14" /> <bean id="bBean" class="cn.powerfully.domain.BBean" p:aBean-ref="aBean">
<!-- <property name="aBean" ref="aBean" /> -->
<property name="list">
<list>
<value>item1</value>
<value>item2</value>
</list>
</property>
<property name="map">
<map>
<entry key="key1" value="1" />
<entry key="key2" value="2" />
</map>
</property>
<property name="props">
<props>
<prop key="key1">1</prop>
<prop key="key2">2</prop>
</props>
</property>
</bean> </beans>

  如果想注入对象,则需要使用ref属性而不是value属性,ref属性值为bean对象的id。特别注意的是,如果使用p或c命名空间,其格式为c:propertyName-ref。常见的集合注入如上配置。关于具体的配置参见帮助文档,毕竟本随笔只是我的知识点简要回忆。

  接着是Java配置,个人觉得Java配置会比xml配置来得更爽,它具有很强的灵活性。还是使用上面的例子,配置如下:

 package cn.powerfully.config;

 import java.util.Arrays;

 import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import cn.powerfully.domain.ABean;
import cn.powerfully.domain.BBean; @Configuration
public class BeanConfig { @Bean
public ABean aBean() {
return new ABean("java configura", 3.1415);
} @Bean
public BBean bBean(ABean aBean) {
BBean bean = new BBean();
bean.setaBean(aBean);
bean.setList(Arrays.asList("item1", "item2"));
return bean;
} }

  通过注解@Configuration来表明该类是配置类,通过@Bean来表示该方法返回结果将放入容器,而方法返回结果即实例对象需要自己创建,其中在容器中bean的id为方法名。对于bBean,需要注入aBean对象,只需要在方法中填入参数,接着在代码里面直接引用即可。

  最后,回忆下注解。一般用到的注解为@Component与@Autowired。@Component标记在类上,表示该类需要被实例化并由Spring容器管理。@Autowired表示需要在Spring容器中查找符合的bean来设置到当前属性里,该注解可以用在字段、构造器、setter上。同时,还要开启自动扫描才能实现。

三、条件化装配

  有时,我们需要动态地来装配bean。当满足一定条件时我们才需要装配这个bean。Spring4之后,注解@Conditional可以实现这个功能。

 @Conditional(UserCondition.class)
public class User {} public class UserCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return false;
}
}

  当UserCondition中matches方法返回真时,才会创建User对象。关于该接口的具体使用请参考另一篇博文(还没写~.~)。

  其中@Profile是其中的一个特例,它也是使用@Conditonal来实现的。配置完该注解后,我们一开始可以通过设置profile类型来管理需要创建哪一系列bean。例如,在Web开发中,我们所选择的数据库可能根据运行时期的不同而不同。例如在开发环境,我们可能使用c3p0、dbcp等作为数据源。而在生产环境中,我们可能使用JNDI数据源。这是我们就可以使用profile了。我们先为不同的配置设置不同的profile,然后再使用时设置profile就行了。具体的还是参考另一篇博文。>_<

  简单例子如下:

  定义交通工具接口

 package cn.powerfully.domain;

 public interface Vehicle {}

  定义车与飞机类并实现Vehicle接口:

 package cn.powerfully.domain;

 import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component; @Component
@Profile("car")
public class Car implements Vehicle {
@Override
public String toString() {
return "Car";
}
}
 package cn.powerfully.domain;

 import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component; @Component
@Profile("plane")
public class Plane implements Vehicle {
@Override
public String toString() {
return "Plane";
}
}

  创建配置类

 package cn.powerfully.config;

 import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; @Configuration
@ComponentScan(basePackages = "cn.powerfully.domain")
public class VehicleConfig {}

  JUnit测试

 package cn.powerfully.test;

 import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import cn.powerfully.config.VehicleConfig;
import cn.powerfully.domain.Vehicle; @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=VehicleConfig.class)
@ActiveProfiles("car")
public class Demo {
@Autowired
private Vehicle vehicle; @Test
public void test(){
System.out.println(vehicle);
}
}

  当选用了car时,输出Car,选择plane时,输出了Plane...当然也可以使用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" xmlns:c="http://www.springframework.org/schema/c"
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"> <beans profile="car">
<bean id="vehicle" class="cn.powerfully.domain.Car" />
</beans> <beans profile="plane">
<bean id="vehicle" class="cn.powerfully.domain.Plane" />
</beans> </beans>

  注意profile属性是位与beans标签上的。