A bean is an object that is instantiated, assembled, and otherwise managed by a Spring IoC container. Otherwise, a bean is simply one of many objects in your application.java
bean是由Spring IoC容器实例化、装配和管理的对象,不然,bean只是应用程序中的众多对象之一。mysql
bean及其之间的依赖关系反映在容器使用的配置元数据中。web
咱们已经了解,Spring IoC容器可以帮咱们操做bean,可是前提是咱们须要配置元数据以告知Spring容器,它才可以经过读取这些配置,来实例化,装配和管理bean对象。spring
而配置元数据的方式,就是咱们今天要总结的三种,分别是XML,Java注解以及Java代码。咱们经过这几种方式,向Spring容器传达这些对象之间丰富的相互依赖关系。sql
该图是Spring如何工做的高级视图。能够看到,应用程序类与配置元数据相结合,在建立并初始化ApplicationContext以后,就能够得到一个彻底配置和可执行的系统或应用程序。数据库
<?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="..." class="..."> <!-- collaborators and configuration for this bean go here --> </bean> <bean id="..." class="..."> <!-- collaborators and configuration for this bean go here --> </bean> <!-- more bean definitions go here --> </beans>
id属性表示bean的惟一标识。安全
class属性定义bean的类型并使用彻底限定的类名。架构
<!-- 1、使用默认构造函数建立,若是没有该默认构造函数,则建立失败。 --> <bean id="userService" class="com.smday.service.impl.UserServiceImpl"></bean> <!-- 2、使用普通公章中的方法建立对象(使用某个类中的方法建立对象,并存入spring容器 --> <bean id="instanceFactory" class="com.smday.factory.InstanceFactory"></bean> <bean id="userService" factory-bean="instanceFactory" factory-method="getUserService"></bean> <!-- 3、使用工厂中的静态方法建立对象 --> <bean id="userService" class="com.smday.factory.StaticFactory" factory-method="getUserService"></bean>
在<bean>
标签的内部定义<constructor-arg>
标签。app
public class ExampleBean { private AnotherBean beanOne; private YetAnotherBean beanTwo; private int i; public ExampleBean( AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) { this.beanOne = anotherBean; this.beanTwo = yetAnotherBean; this.i = i; } }
<bean id="exampleBean" class="examples.ExampleBean"> <!-- constructor injection using the nested ref element --> <constructor-arg> <ref bean="anotherExampleBean"/> </constructor-arg> <!-- constructor injection using the neater ref attribute --> <constructor-arg ref="yetAnotherBean"/> <constructor-arg type="int" value="1"/> </bean> <bean id="anotherExampleBean" class="examples.AnotherBean"/> <bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
value:用于提供基本类型和String类型的数据。框架
ref:用于提供其余的bean类型数据,在spring的ioc核心容器中出现过的bean对象。
在建立对象时,若是没有提供构造器中的这些参数,将没法建立该对象。
在<bean>
标签的内部定义<property>
标签。
public class ExampleBean { private AnotherBean beanOne; private YetAnotherBean beanTwo; private int i; public void setBeanOne(AnotherBean beanOne) { this.beanOne = beanOne; } public void setBeanTwo(YetAnotherBean beanTwo) { this.beanTwo = beanTwo; } public void setIntegerProperty(int i) { this.i = i; } }
<bean id="exampleBean" class="examples.ExampleBean"> <!-- setter injection using the nested ref element --> <property name="beanOne"> <ref bean="anotherExampleBean"/> </property> <!-- setter injection using the neater ref attribute --> <property name="beanTwo" ref="yetAnotherBean"/> <property name="integerProperty" value="1"/> </bean> <bean id="anotherExampleBean" class="examples.AnotherBean"/> <bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
name:指定注入时调用的set方法的属性名称。
value:提供基本类型和String类型的数据。
ref:提供其余的bean类型数据,在spring的ioc核心容器中出现过的bean对象。
若是某个成员必须有值,但并无提供相应的setter方法,将会出错。
【集合类型的注入】:分为list和map两类结构
<bean id="userService" class="com.smday.service.impl.UserServiceImpl"> <property name="myStrs"> <array> <value>AAA</value> <value>BBB</value> <value>BBB</value> </array> </property> <property name="myList"> <list> <value>AAA</value> <value>BBB</value> <value>BBB</value> </list> </property> <property name="mySet"> <set> <value>AAA</value> <value>BBB</value> <value>BBB</value> </set> </property> <property name="myMap"> <map> <entry key="testA" value="AAA"></entry> <entry key="testB" > <value>BBB</value> </entry> </map> </property> <property name="myProp"> <props> <prop key="testC">CCC</prop> <prop key="testD">DDD</prop> </props> </property> </bean>
list结构可使用list、array和set标签。
map结构可使用map和props标签。
1、p-namespace使用bean元素的属性来提供属性值和协做bean,而不是使用嵌套的<property/>
元素,下面两段bean的配置效果相同。
<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"> <!-- 传统的xml声明 --> <bean name="classic" class="com.example.ExampleBean"> <property name="email" value="foo@bar.com"/> </bean> <!-- p-namespace 声明 --> <bean name="p-namespace" class="com.example.ExampleBean" p:email="foo@bar.com"/> </beans>
2、Spring 3.1中新引入的c-namespace容许使用内联属性来配置构造函数参数,而不是使用嵌套的<constructor-arg>
。
<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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="bar" class="x.y.Bar"/> <bean id="baz" class="x.y.Baz"/> <!-- 传统的xml声明 --> <bean id="foo" class="x.y.Foo"> <constructor-arg ref="bar"/> <constructor-arg ref="baz"/> <constructor-arg value="foo@bar.com"/> </bean> <!-- c-namespace 声明 --> <bean id="foo" class="x.y.Foo" c:bar-ref="bar" c:baz-ref="baz" c:email="foo@bar.com"/> </beans>
这两个注解类是Spring's new java-configuration的核心构件。
@Bean注解用于指示方法实例化、配置和初始化要由Spring IoC容器管理的新对象,@Bean注解的做用与<bean/>
标签相同。简单的理解就是这个注解能够告知spring,这个方法上面将来但愿注册一个应用上下文的bean对象,所以用@Bean注解的方法须要利用Java代码,定义返回一个bean实例的逻辑。
@Configuration注解一个类代表这个类的主要目的是做为bean定义的源,@Configuration类容许经过简单地调用同一类中的其余@Bean方法来定义bean之间的依赖关系。简单的理解就是一个配置类,自此以后,你能够在该配置类中完成在xml中完成的事,但形式会有所不一样。
下面这个例子是一个最简单的配置类的定义:
@Configuration public class AppConfig { @Bean public MyService myService() { return new MyServiceImpl(); } }
它的做用和下面这段xml配置的方式等价:
<beans> <bean id="myService" class="com.acme.services.MyServiceImpl"/> </beans>
一个@Bean注释的方法能够有任意数量的参数来描述构建该bean所需的依赖关系。例如,若是咱们的TransferService须要一个AccountRepository,咱们能够经过一个方法参数来实现这个依赖:
@Configuration public class AppConfig { @Bean public TransferService transferService(AccountRepository accountRepository) { return new TransferServiceImpl(accountRepository); } }
当spring调用transferService方法建立bean时,会自动装配accountRepository到配置方法中,再次印证了那句话,带有@Bean注解的方法能够编写任何须要的Java代码来产生Bean的实例,例如构造器,setter方法,以及任何能够产生实例的方法。
AnnotationConfigApplicationContext是Spring 3.0中新增的。它不只能够接受@Configuration配置类做为输入,还能够接受普通的@Component类和使用JSR-330元数据注释的类。
初始化spring容器,获取Myservice对象,调用对象的方法。
public static void main(String[] args) { ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class); MyService myService = ctx.getBean(MyService.class); myService.doStuff(); }
默认状况下,配置类将会使用@Bean注解的方法的名称做为bean的名称,这一点能够经过name属性修改。
@Configuration public class AppConfig { @Bean(name = "myFoo") public Foo foo() { return new Foo(); } }
如上:若是没有指定name属性,该bean的名称为foo,若是指定了name属性,这里的名称就是myFoo。
Spring从如下两个角度实现自动装配:
首先仍是来看一段简单的例子:
//定义一个UserService接口 public interface UserService { void add(); }
//定义实现类,注意加上@Component注解,告知spring建立这个bean @Component public class NormalUserServiceImpl implements UserService { @Override public void add() { System.out.println("添加用户"); } }
//controller层,注意@Autowired注解,自动按类型注入Userservice @Component public class UserController { @Autowired private UserService userservice; public void add(){ userservice.add(); } }
//定义配置类,注意@ComponentScan("com.my.demo")注解开启组件扫描 @Configuration @ComponentScan("com.my.demo") public class Appconfig { }
//整合junit测试类进行测试 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = Appconfig.class) public class UserServiceTest { @Autowired private UserService userservice; @Test public void testMethod(){ userservice.add(); } }
以上就是一套能够正常运行的简单案例,固然其中有很多可能出现的问题或者是其余能够实现相同功能的方案,咱们都暂且不提。其中出现了许多自动化装配bean的注解,咱们一一来看:
【@Component】
值得一提的是,在三层架构中,Spring框架提供了明确的三层注释,做用与@Component相同,但语义更加清晰明了,分别是:
Controller:表现层、Service:业务层、Respository:持久层
【@Autowired】
当出现歧义性时,知足类型要求的bean不是惟一时,能够考虑使用@Qualifier和@Resource注解,参考:Spring解决自动装配歧义性的几种方案
【@Configuration】
【@ComponentScan】
设置spring组件扫描的基础包的几种方案:
@ComponentScan("com.my.demo")
@ComponentScan(basePackages = {"com.my.demo.web","com.my.demo.service"})
@ComponentScan(basePackageClasses = {UserController.class, UserService.class, UserDao.class})
,相较于第二种,较为安全。
须要注意的是,组件扫描默认是不开启的,咱们须要经过该注解显式通知Spring,告诉它去寻找带有@Component注解的类,去建立该类的bean对象。
开启组件扫描的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: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 https://www.springframework.org/schema/context/spring-context.xsd"> <!--配置扫描,至关于@ComponentScan("com.my.demo")--> <context:component-scan base-package="com.my.demo"/> </beans>
既然使用xml方式开启组件扫描,那么测试的时候须要谨慎,要读取该xml文件:@ContextConfiguration("classpath:applicationContext.xml")
。
直接以例子呈现:
#jdbcConfig.properties jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/spring jdbc.username=root jdbc.password=123456
/** * @author Summerday * <p> * 和spring链接数据库相关的配置类 */ public class JdbcConfig { @Value("${jdbc.driver}") private String driver; @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String username; @Value("${jdbc.password}") private String password; /** * 建立queryRunner对象 * * @param dataSource * @return */ @Bean(name = "runner") @Scope("prototype") public QueryRunner createQueryRunner(DataSource dataSource) { return new QueryRunner(dataSource); } /** * 建立数据源对象 * * @return */ @Bean(name = "dataSource") public DataSource createDataSource() { try { ComboPooledDataSource ds = new ComboPooledDataSource(); ds.setDriverClass(driver); ds.setJdbcUrl(url); ds.setUser(username); ds.setPassword(password); return ds; } catch (Exception e) { throw new RuntimeException(e); } } }
【@Value】
/** * 主配置类 */ @Configuration @ComponentScan(basePackages = "com.smday") @Import(JdbcConfig.class) @PropertySource("classpath:JdbcConfig.properties") public class SpringConfiguration { }
【@Import】
【@PropertySource】
最后的最后,引用Spring in Action中做者的话:自动化配置、基于Java的显式配置以及基于xml的显式配置都描述了Spring应用中组件以及这些组件之间的关系。做者建议尽量使用自动化的配置,其次若是须要显式配置,但愿优先选择基于Java的配置,类型安全且易懂。