传统的spring做法是使用.xml文件来对bean进行注入或者配置AOP、事务,这么做有两个缺点:
1、如果所有的内容都配置在.xml文件中,那么.xml文件将会十分庞大。如果按需求分开.xml文件,name.xml文件又会非常多。总之这将导致配置文件的可读性和可维护性变得很低。
2、在开发中.java文件和.xml文件之间的的不断切换,是一件很麻烦的事情,同时思维上的不连贯会降低开发效率
为了解决这两个问题,spring引入了 注解,通过“@xxx"的方式,让注解与java bean紧密结合,即减少了配置文件的体积,又增加了java bean的可读性。
基于类的注解:
@Component是一个通用注解,可用于任何bean
@Repository, @Service, @Controller是更有针对性的注解
- @Repository通常用于注解DAO类,即持久层
- @Service 通常用于注解Service类,即服务层
- @Controller 通常用于注解Controller,即控制层(MVC)
类的自动检测及bean的注册
。spring可以自动检测类并注册bean到ApplicationContext中
//基于类的注解
@Service
public class SimpleMovieLister{
private MovieFinder movieFinder;
//方法和成员变量的注解,可以被spring自动检测到的
@Autowired
public SimpleMovieLister(MovieFinder movieFinder){
this.movieFinder = movieFinder;
}
}
<context:annotation-config/>
。通过在基于xml的Spring配置如下标签
。<context:annotation-config/>仅会 查找在同一个application中的bean注解
<?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:annotation-config/>
</beans>
类的自动检测及Bean的注册
。为了能够检测这些类并注册相应的Bean,需要下面内容
<?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:component-scan base-package="com.example" />
</beans>
<context:component-scan/>会完成组件的扫描,基于类注解的这种扫描。扫描到类的注解,把这样的类注册到IOC容器中去。
base-package属性:扫描这个包下的所有类
<context:component-scan/>包含了 <context:annotation-config/>,通常使用前者后,不用在使用后者。使用过滤器进行自定义的扫描
。默认情况下,类被自动发现并注册bean的条件是:使用@Component,@Repository,@Service,@Controller注解或者使用@Component的自定义注解
。可以通过过滤器修改上面的行为,如:下面例子的xml配置忽略所有的@Reponsitory注解并用”Stub“代替
<bean
<context:component-scan base-backage="org.example">
//这是个包含的过滤器,类型regex是以通配符的形式来找stub和Responsitory这样的类
<context:include-filter type="regex" expression=".*Stub.*Reponsitory"/>
//排除的过滤,类型是注解。排除所有用Responsitory来注解的类
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Responsitory"/>
</context:component-scan>
</bean>
。还可以使用use-default-filters="false" 禁止自动发现与注册
定义Bean
。扫描过程中组件被自动检测,那么bean名称是由BeanNameGenerator生成的(@Component,@Repository,@Service,@Controller都会有个name属性用于显示设置Bean Name)
//可以显式的指定这个类在注册到IOC容器中它所对应的类,相当于xml配置文件中的id
@Service"myMovieLister"
public class SimpleMovieLister{
//...
}
//没有显式指定这个类的名称,它会根据BeanNameGenerator来自动生成它的id,
//规则是以类名为基础并把类名的第一个字母小写,把这个字符串作为bean的id
@Repository
public class MovieFinderImpl implements MovieFinder{
//...
}
。可以自定义bean命名策略,实现BeanNameGenerator接口,并一定要包含一个无参构造器
<beans>
//使用自己定义的命名策略
<context:component-scan base-package="org.example" name-generator="org.example.MyNameGenerator"/>
</beans
作用域(scope)
。通常情况下自动查找的Sring组件,其scope是singleton(单例模式),这样只会创建一个Action对象,每次访问都是同一个对象,数据不安全。@Scope("prototype")可以保证,当有请求的时候,都会创建一个Action对象
@Scope("prototype")
@Repository
public class MovieFinderImpl implements MovieFinder{
//...
}
@Required
。@Required注解适用于bean属性的setter方法
。这个注解仅仅表示,受影响的bean属性必须在配置时被填充,通过在bean定义或通过自动装配一个明确的属性值
@Autowired
。比较常用,自动装配。可以将@Autowired注解为”传统“的setter方法
private MovieFinder movieFinder;
@Autowired
public void setMovieFinder(MovieFinder movieFinder){
this.movieFinder=movieFinder;
}
。也可以用于构造器或成员变量
public class MovieRecommender{
@Autowired
private MovieCatalog movieCatalog;
private CustomerDao cutomerDao;
@Autowired
public MovieRecommender(CustomerDao cutomerDao){
this.cutomerDao=cutomerDao;
}
}
。默认情况下,如果因找不到合适的bean将会导致autowiring失败抛出异常,可以通过设置@Autowired(required=false)。意思是:如果找不到bean的实例是不会抛出异常的,只有在使用的时候才会发现movieFinder是null。在使用的时候最好判断下是否为空。
public class SimpleMovieLister{
private MovieFinder movieFinder;
@Autowired(required=false)
public void setMovieFinder(MovieFinder movieFinder){
this.movieFinder=movieFinder;
}
}
。每个类只能有一个构造器被标注为required=true;
。@Autowired的必要属性,建议使用@Required注解
。可以使用@Autowired注解哪些众所周知的解析依赖性接口,比如:BeanFactory,ApplicationContext,Environment,ResourceLoader,ApplicationEventPublisher,MessageSource
。可以通过添加注解给需要该类型的数组的字段或方法,以提供ApplicationContext中的所有特定类型的bean
private Set<MovieCatalog> movieCatalogs;
//可以注解在数组上,当前的ApplicationContext中所有是set泛型中声明的bean或它的子类都可以被@Autowired注解。
//然后把这些bean的实例都放到当前的结合当中去
@Autowired
public void setMovieCatalog(Set<MovieCatalog movieCatalogs){
this.movieCatalogs = movieCatalogs;
}
。可以用于装配key为String的Map
。如果希望数组有序,可以让bean实现 org.springframeworke.core.Ordered接口或使用@Order注解
@Qualifier
。按类型自动装配多个bean实例的情况下,可以使用Spring的@Qualifier注解缩小范围(或指定唯一值),也可以用于指定单独的构造器参数或方法参数。
。可用于注解集合类型变量
。@Autowired适用于fields,constructor, multi-argument, methods这些允许在参数级别使用@Qualifier注解缩小范围的情况
。@Resource 适用于成员变量、只有一个参数的setter方法,所以在目标是构造器或一个多参数方法时,最好的方式是使用qualifiers
基于java容器的注解
。@Bean 标识一个用于配置和初始化一个由SpringIOC容器管理的新对象的方法,类似XML配置文件的<bean/>
。可以在Spring的@Component注解的类中使用@Bean注解任何方法
。通常和@Bean结合使用的是@Configuration,而不是@Component
@Configuration
public class AppConfig{
@Bean
public MyService myservice(){
return new MyServiceImpl;
}
}
相当于
<beans>
<bean id="myService" class="com.services.MyServiceImpl"/>
</beans>
上面两个方法效果是一样的。
用@Bean注解方法,是以方法名为作为id
例:
public class Foo{
public void init(){
//init
}
}
public class Bar{
public void clearup(){
//clearup
}
}
@Configuration
public class AppConfig{
@Bean(initMethod="init")
public Foo foo(){
return new Foo();
}
@Bean(destroyMethod="clearup")
public Bar bar(){
return new Bar();
}
}
使用@ImportSource和@Value注解进行资源文件读取
spring配置Datasource,建立连接是只要有连接就新建一个connection,没有连接池的作用。
<beans>
<context:annotation-config/>
//加载资源文件的配置
<context:property-placeholder location="classpath:/com/acme/jdbc.properties"/>
<bean class="com.acme.AppConfig"></bean>
<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource">
//获取properties文件的内容 通过键"url" 获取其value的内容
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
</beans>
使用注解配置
@Configuration
@ImportResource("classpath:/com/acme/properties-config.xml")
public class AppConfig{
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean
public DataSource dataSource(){
return new DriverManagerDataSource(url,username,password);
}
}