您的位置:首页 > 编程语言 > Java开发

Spring基于annotation的依赖注入实现

2015-05-27 16:16 423 查看

Spring基于annotation的依赖注入实现

一、工作目的

以前通常我们将Action、Service、Dao层的对象都以配置文件的形式交给Spring管理,Spring将各层的对象以松耦合的方式组织在一起,Action对象无须关心Service对象的具体实现,Service对象无须关心持久层对象的具体实现,各层对象的调用完全面向接口。当系统需要重构时,代码的改写量将大大减少。不过上述方式有一定的局限性,试想我们的系统规模比较大的时候,需要交给Spring管理的Bean数量庞大,如果都写在Spring配置文件applicationContext.xml中,代码的可读性、可维护性会变得很差。本例将简要介绍
Spring中常使用的annotation,并以演示通过annotation的方式完成Spring的依赖注入。

二、具体内容及步骤

Spring3.0 以前,使用 XML 进行依赖配置几乎是唯一的选择。Spring 3.0 的出现改变了这一状况,它提供了一系列的针对依赖注入的注解,这使得Spring IoC 在 XML 文件之外多了一种可行的选择。

1、将类标识为 Bean

使用@Repository、@Service、@Controller和@Component,@Repository 注解属于最先引入的一批,它用于将数据访问层 (DAO 层 ) 的类标识为 Spring Bean。具体只需将该注解标注在 DAO 类上即可。同时,为了让 Spring 能够扫描类路径中的类并识别出 @Repository 注解,需要在 XML 配置文件中启用 Bean 的自动扫描功能,这可以通过 <context:component-scan/>
实现。如下所示:

<span style="font-family:Times New Roman;"><!-- Spring搜索路径配置,如下配置将搜索工程com目录下标识的Bean-->
<context:annotation-config />
<context:component-scan base-package="com" >
</context:component-scan></span>


这样我们不再需要在XML中显式使用 <bean/> 进行 Bean 的配置。Spring 在容器初始化时将自动扫描 base-package 指定的包及其子包下的所有 class 文件,所有标注了@Repository、@Service、@Controller、@Component 的类都将被注册为 Spring Bean。

●@Component 是一个泛化的概念,仅仅表示一个组件 (Bean) ,可以作用在任何层次。

●@Service 通常作用在业务层,但是目前该功能与 @Component 相同。

●@Constroller 通常作用在控制层,但是目前该功能与 @Component 相同。

●@Repository 通常用在持久层,但是目前该功能与 @Component 相同。

通过在SSH框架不同层的类上使用 @Repository、@Service 和 @Constroller 注解,Spring 会自动创建相应的 BeanDefinition 对象,并注册到 ApplicationContext 中。这些类就成了 Spring 受管组件。通常在程序中,为了便于开发,各层都使用@Component进行注解,如图:

@Component("staffDao")
public class staffDaoImp implements staffDao{
/*...代码...*/
}


通常使用"name"的形式生成Bean的名称,还有一种方式实现 BeanNameGenerator 接口,确认包含了一个默认的无参数构造方法。然后在配置扫描器时使用属性name-generator.使用Spring管理Bean默认作用域的是singleton,容器中只存在一个实例,也可以通过@Scope指定作用域为prototype,容器在接受到请求的时候,会每次都重新生成一个新的对象给请求方。

2、指定 Bean 的自动装配策略
自动装配是指,Spring在装配Bean的时候,根据指定的自动装配规则,将某个Bean所需要引用类型的Bean注入进来。通常使用 @Resource、@Autowired 和@Qualifier。

①@Autowired 和 @Qualifier

使用 @Autowired 注解进行装配,只能是根据类型进行匹配。@Autowired 注解可以用于 Setter 方法、构造函数、字段,甚至普通方法,前提是方法必须有至少一个参数。@Autowired 标注作用于普通方法时,会产生一个副作用,就是在容器初始化该 Bean 实例的时候就会调用该方法。当然,前提是执行了自动装配,对于不满足装配条件的情况,该方法也不会被执行。此时与@Qualifier的配合使用可以实现根据Bean的byName自动注入,例如:
@Autowired  @Qualifier("personDaoBean")
private PersonDao  personDao;


如图代码:如果不使用@Qualifier指定要装配的Bean名称,Spring会将容器里类型为PersonDao的Bean装配给该类(根据类型装配原则),当然通过代码的控制可以实现业务的要求,不过各层的耦合会比较严重,不符合Spring松耦合的理念,通常推荐@Autowired、@Qualifier配合使用完成ByName装配,下面将介绍更方便的byName装配方式,@Resource。

②@Resource

如果希望根据 name 执行自动装配,那么应该使用JSR-250提供的@Resource 注解,而不应该使用@Autowired与@Qualifier的组合。@Resource使用 byName 的方式执行自动封装。@Resource 标注可以作用于带一个参数的 Setter 方法、字段,以及带一个参数的普通方法上。@Resource 注解有一个 name 属性,用于指定Bean在配置文件中对应的名字。如果没有指定name属性,那么默认值就是字段或者属性的名字。@Resource和@Qualifier的配合虽然仍然成立,但是
@Qualifier对于@Resource而言,几乎与name属性等效。如下:
@ Resource (name="personDaoBean")
private PersonDao  personDao;


3、实例演示

①Spring配置文件applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<!-- Spring搜索路径配置 -->
<context:annotation-config />
<context:component-scan base-package="com" >
</context:component-scan>
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName"
value="com.mysql.jdbc.Driver">
</property>
<property name="url" value="jdbc:mysql://localhost:3306/hibernate_cascade_query"></property>
<property name="username" value="root"></property>
<property name="password" value="123123"></property>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"
p:dataSource-ref="dataSource"
p:configLocation="classpath:config/hibernate.cfg.xml" >
</bean>
</beans>


通过配置文件可以看出,我们不再像之前SSH框架搭建例子里,使用:

<bean id="userDao"  class="com.dao.imp.userDaoImp">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>


的方式,在配置文件中完成依赖注入。hibernate配置文件、日志文件的配置同SSHSSH框架搭建Demo里面相同,不再赘述。
②Dao实现层
@Component("staffDao")
public class staffDaoImp implements staffDao{
@Resource
private SessionFactory sessionFactory;

public SessionFactory getSessionFactory() {
return sessionFactory;
}

public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
/*
...code...
*/
用到的第一个annotation,@Component("staffDao")将class staffDaoImp类标识为Bean交给Spring管理,staffDao为该Bean 的名字。当程序运行的时候,读Spring配置文件,根据:

<context:annotation-config />
<context:component-scan base-package="com" >
</context:component-scan>

搜索com目录,将Component标识的Bean注入到Spring容器。@Resource没有指定name属性,默认值是字段或者属性的名字即装配Spring容器中名为sessionFactory的Bean,sessionFactory的注入是通过配置文件的方式完成的。一般情况下,系统级的Bean通过配置文件的方式注入,业务级的Bean通过annotation注入。

③Service实现层
@Component("staffService")
public class staffServiceImp implements staffService{

@Resource(name="staffDao")
private staffDao staffDao;

public staffDao getStaffDao() {
return staffDao;
}

public void setStaffDao(staffDao staffDao) {
this.staffDao = staffDao;
}
/*
...code...
*/

@Component("staffService")的功能是将class staffServiceImp类交给Spring容器管理,@Resource(name="staffDao")的作用装配名为staffDao的Bean,面前我们已经将staffDaoImp类标识为staffDao并注入到了Spring容器。name属性值必须与之前注入的保持一致。

④Action层
@Component("staffAction")
public class staffAction extends ActionSupport implements ServletRequestAware,
ServletResponseAware {
private static final long serialVersionUID = 1L;
private HttpServletRequest request;
private HttpServletResponse response;
@Resource(name="staffService")
private staffService staffService;
private String staffName;
/*
staffService的Getter()、Setter()
....
*/


@Resource(name="")也可以放到Setter()方法之上:
public staffService getStaffService() {
return staffService;
}
@Resource(name="staffService")
public void setStaffService(staffService staffService) {
this.staffService = staffService;
}


两种方法的效果是相同的,可以根据自己的习惯,选择性使用
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: