通过对前面Hibernate的学习可以知道,对框架的配置都有Xml和Annotation两种方式。Xml配置的优势在于可以在不知道源码的情
况下进行配置,而Annotation的配置方式则更加方便。前面两节介绍了Xml的配置方式,下面就对基于Annotation的配置方式做一个简
单介绍。
利用注解配置有很多优势:
1、它可以充分利用Java反射机制获取类结构信息,这些信息可以有效减少配置的工作。
2、注释和Java代码位于一个文件中,而Xml配置采用的是独立的配置文件,大多数情况下配置信息在程序开发完成后都不会调
整,如果配置信息和Java代码放在一起,有助于增强程序的内聚。而采用独立的XML配置文件,在编写功能时,往往需要在程序文件
和配置文件中不停切换,降低开发效率。
因此,接下来就对常用的Annotation进行学习。首先,为了能够让注解工作,需要在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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config></context:annotation-config>
</beans>
引入了特定的命名空间后,加入
<context:annotation-config></context:annotation-config>
便可以在程序中进行基于Annotation的基础开发。一、@Autowired
它可以对类成员变量、方法以及构造函数进行标注,完成自动装配。
一般来说,该注解标注在setter方法上,利用setter机制注入对象:
@Autowired
public void setUserDAO(@Qualifier(value="userDAO")UserDAO userDAO) {
this.userDAO = userDAO;
}
该注解默认的方式是byType,按类型注入。当然也可以利用byName,不过要标注上@Qualifier,将value指定为要装载的名字。
也可以注解一般方法:
@Autowired
public void prepare(@Qualifier(value="userDAO1")UserDAO userDAO1,@Qualifier(value="userDAO2")UserDAO userDAO2) {
this.userDAO1 = userDAO1;
this.userDAO2 = userDAO2;
}
也可以注解构造方法:
@Autowired
public UserServiceImpl(UserDAO userDAO) {
super();
this.userDAO = userDAO;
}
则此时是采用构造方法的方式注入。
二、@Resource
其作用相当于@Autowired,不过后者是按byType注入,而@Resource是默认按照byName方式注入。其中有两个比较重要的
属性,name和type,由于默认是byName方式注入,所以需要保证名字和容器创建的对象相同,否则会抛出异常。
三、@Component
以上两个标签实现了注入的功能,然而此时bean还是需要在xml文件中定义。因此从Spring2.5开始,提供了@Component注解,达
到从xml配置文件中完全移除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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config></context:annotation-config>
<context:component-scan base-package="cn.wqy"></context:component-scan>
</beans>
该行代码让容器去指定的包目录下寻找被@Component注解了的类,将其当做一个组件,这个组件在别的类调用时就可以看做一个
对象资源。
UserServiceImpl.java:
package cn.wqy.biz;
import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import cn.wqy.DAO.UserDAO;
import cn.wqy.model.User;
@Component("userService")
public class UserServiceImpl implements UserService {
private UserDAO userDAO;
public UserDAO getUserDAO() {
return userDAO;
}
@Resource
public void setUserDAO(@Qualifier(value="userDAO")UserDAO userDAO) {
this.userDAO = userDAO;
}
@Override
public void addUser(User user) {
// TODO Auto-generated method stub
userDAO.add(user);
}
}
UserDAO.java:
package cn.wqy.DAO;
import org.springframework.stereotype.Component;
import cn.wqy.model.User;
@Component("userDAO")
public class UserDAOImpl implements UserDAO {
@Override
public void add(User user) {
// TODO Auto-generated method stub
System.out.println("A user added");
}
}
之所以指定组件的名字很重要,因为注入的根据就是name,如果名字不同,会抛出异常,找不到对应的对象。
Ps:需要注意的一点:
在目前的Spring版本中,以下几个标签作用相同:@Component、@Controller、@Service、@Repository。
1、@Component是所有受Spring管理的组件的通用形式;
2、@Control对应与表现层的Bean,即Action:
@Controller
@Scope(value="prototype")
public class UserAction{
...
}
使用@Controller注解标识UserAction之后,就表示要把UserAction交给Spring容器管理,在Spring容器中会存在一个名字
为"userAction"的action,这个名字是根据UserAction类名来取的。注意:如果@Controller不指定其value【@Controller】,则默认
的bean名字为这个类的类名首字母小写,如果指定value【@Controller(value="UserAction")】或者
【@Controller("UserAction")】,则使用value作为bean的名字。
这里的UserAction还使用了@Scope注解,@Scope("prototype")表示将Action的范围声明为原型,可以利用容器的
scope="prototype"来保证每一个请求有一个单独的Action来处理,避免struts中Action的线程安全问题。spring 默认scope 是单例模
式(scope="singleton"),这样只会创建一个Action对象,每次访问都是同一Action对象,数据不安全,struts2 是要求每次次访问都对
应不同的Action,scope="prototype" 可以保证当有请求的时候都创建一个Action对象。
3、@Service对应业务层的Bean
package cn.wqy.biz;
import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import cn.wqy.DAO.UserDAO;
import cn.wqy.model.User;
@Service("userService")
public class UserServiceImpl implements UserService {
private UserDAO userDAO;
public UserDAO getUserDAO() {
return userDAO;
}
}
4、@Repository对应数据访问层的Bean,即DAO层
package cn.wqy.DAO;
import org.springframework.stereotype.Repository;
import cn.wqy.model.User;
@Repository("userDAO")
public class UserDAOImpl implements UserDAO {
@Override
public void add(User user) {
// TODO Auto-generated method stub
System.out.println("A user added");
}
}
定义bean的生命范围,注解在实体类名上,表明该对象组件的生命范围。
五、@PostConstruct & @PreDestroy
@PostConstruct
public void before(){
}
@PreDestroy
public void after(){
}
分别对应init-method和destroy-method,注解在方法之上,分别在bean初始化完成后及bean销毁前执行。