用注解来向Spring容器注册Bean。需要在applicationContext.xml中注册<context:component-scan base-package=”pagkage1[,pagkage2,…,pagkageN]”/>。
如:在base-package指明一个包
<context:component-scan base-package="cn.gacl.java"/>
表明cn.gacl.java包及其子包中,如果某个类的头上带有特定的注解【@Component/@Repository/@Service/@Controller】,就会将这个对象作为Bean注册进Spring容器。也可以在<context:component-scan base-package=” ”/>中指定多个包,如:
<context:component-scan base-package="cn.gacl.dao.impl,cn.gacl.service.impl,cn.gacl.action"/>
多个包逗号隔开。
一、基于@Component注解的配置
spring 2.5 中除了提供 @Component 注释外,还定义了几个拥有特殊语义的注释,它们分别是:@Repository、@Service 和 @Controller。
在目前的 Spring 版本中,这 3 个注释和 @Component 是等效的,但是从注释类的命名上,很容易看出这 3 个注释分别和持久层、业务层和控制层(Web 层)相对应。
虽然目前这3 个注释和 @Component 相比没有什么新意,但 Spring 将在以后的版本中为它们添加特殊的功能。所以,如果 Web 应用程序采用了经典的三层分层结构的话,最好在持久层、业务层和控制层分别采用上述注解对分层中的类进行注释。
1、@controller 控制器(注入服务)
2、@service 服务(注入dao)
4、@component (把普通pojo实例化到spring容器中,相当于配置文件中的<bean id="" class=""/>)
@component用法如下:
- @Component("userDao")
- public class UserDaoImp implements UserDao{
- @Override
- public void add(User user) {
- System.out.println(user.getName());
- System.out.println(user.getSex());
- System.out.println(user.getAge());
- }
- }
@Component("userDao")
public class UserDaoImp implements UserDao{
@Override
public void add(User user) {
System.out.println(user.getName());
System.out.println(user.getSex());
System.out.println(user.getAge());
}
}
在类上使用@Component注解,表示该类定义为Spring管理Bean,使用默认value(可选)属性表示Bean标识符。
相当于:
- <bean id="userDao" class="com.mucfc.dao.UserDao"/>
<bean id="userDao" class="com.mucfc.dao.UserDao"/>
@Component,@Service,@Controller,@Repository注解的类,并把这些类纳入进spring容器中管理。下面写这个是引入component的扫描组件
- <!-- 配置的bean所在包的位置 -->
- lt;context:component-scan base-package="com.mucfc" />
<!-- 配置的bean所在包的位置 -->
<context:component-scan base-package="com.mucfc" />
其中base-package为需要扫描的包(含所有子包) @Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
二、使用实例
User.Java:用@Repository注解
- package com.mucfc.model;
- import org.springframework.context.annotation.Scope;
- import org.springframework.stereotype.Repository;
- @Repository("user")
- @Scope("prototype")
- //@Repository用于标注数据访问组件,即DAO组件
- //@Scope("prototype")让其每次返回不同的实例,默认是单例
- public class User {
- private String name;
- private String sex;
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getSex() {
- return sex;
- }
- public void setSex(String sex) {
- this.sex = sex;
- }
- public int getAge() {
- return age;
- }
- public void setAge(int age) {
- this.age = age;
- }
- private int age;
- }
package com.mucfc.model;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Repository;
@Repository("user")
@Scope("prototype")
//@Repository用于标注数据访问组件,即DAO组件
//@Scope("prototype")让其每次返回不同的实例,默认是单例
public class User {
private String name;
private String sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
private int age;
}
UserDao.java- package com.mucfc.dao;
- import com.mucfc.model.User;
- public interface UserDao {
- public void add(User user);
- }
package com.mucfc.dao;
import com.mucfc.model.User;
public interface UserDao {
public void add(User user);
}
UserDaoImp.java:用@Controller注解- package com.mucfc.daoimp;
- import org.springframework.stereotype.Controller;
- import com.mucfc.dao.UserDao;
- import com.mucfc.model.User;
- @Controller("userDao")
- //@Controller用于标注控制层组件
- public class UserDaoImp implements UserDao{
- @Override
- public void add(User user) {
- System.out.println(user.getName());
- System.out.println(user.getSex());
- System.out.println(user.getAge());
- }
- }
package com.mucfc.daoimp;
import org.springframework.stereotype.Controller;
import com.mucfc.dao.UserDao;
import com.mucfc.model.User;
@Controller("userDao")
//@Controller用于标注控制层组件
public class UserDaoImp implements UserDao{
@Override
public void add(User user) {
System.out.println(user.getName());
System.out.println(user.getSex());
System.out.println(user.getAge());
}
}
@Controller对应表现层的Bean,也就是Action,例如:
1 @Controller
2 @Scope("prototype")
3 public class UserAction extends BaseAction<User>{
4 ……
5 }
使用@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对象
- package com.mucfc.service;
- import javax.annotation.Resource;
- import org.springframework.stereotype.Service;
- import com.mucfc.dao.UserDao;
- import com.mucfc.model.User;
- @Service("userService")
- //@Service用于标注业务层组件
- public class UserService {
- //setter注入接口、面向接口编程
- private UserDao userdao ;
- public void add(User user){
- userdao.add(user) ;
- }
- public UserDao getUserdao() {
- return userdao;
- }
- //注解
- @Resource(name="userDao")
- public void setUserdao(UserDao userdao) {
- this.userdao = userdao;
- }
- }
package com.mucfc.service;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import com.mucfc.dao.UserDao;
import com.mucfc.model.User;
@Service("userService")
//@Service用于标注业务层组件
public class UserService {
//setter注入接口、面向接口编程
private UserDao userdao ;
public void add(User user){
userdao.add(user) ;
}
public UserDao getUserdao() {
return userdao;
}
//注解
@Resource(name="userDao")
public void setUserdao(UserDao userdao) {
this.userdao = userdao;
}
}
注意:在Action声明的“userService”变量的类型必须是“UserServiceImpl”或者是其父类“UserService”,否则由于类型不一致而无法注入,由于Action中的声明的“userService”变量使用了@Resource注解去标注,并且指明了其name = "userService",这就等于告诉Spring,说我Action要实例化一个“userService”,你Spring快点帮我实例化好,然后给我,当Spring看到userService变量上的@Resource的注解时,根据其指明的name属性可以知道,Action中需要用到一个UserServiceImpl的实例,此时Spring就会把自己创建好的名字叫做"userService"的UserServiceImpl的实例注入给Action中的“userService”变量,帮助Action完成userService的实例化,这样在Action中就不用通过“UserService userService = new UserServiceImpl();”这种最原始的方式去实例化userService了。如果没有Spring,那么当Action需要使用UserServiceImpl时,必须通过“UserService userService = new UserServiceImpl();”主动去创建实例对象,但使用了Spring之后,Action要使用UserServiceImpl时,就不用主动去创建UserServiceImpl的实例了,创建UserServiceImpl实例已经交给Spring来做了,Spring把创建好的UserServiceImpl实例给Action,Action拿到就可以直接用了。Action由原来的主动创建UserServiceImpl实例后就可以马上使用,变成了被动等待由Spring创建好UserServiceImpl实例之后再注入给Action,Action才能够使用。这说明Action对“UserServiceImpl”类的“控制权”已经被“反转”了,原来主动权在自己手上,自己要使用“UserServiceImpl”类的实例,自己主动去new一个出来马上就可以使用了,但现在自己不能主动去new“UserServiceImpl”类的实例,new“UserServiceImpl”类的实例的权力已经被Spring拿走了,只有Spring才能够new“UserServiceImpl”类的实例,而Action只能等Spring创建好“UserServiceImpl”类的实例后,再“恳求”Spring把创建好的“UserServiceImpl”类的实例给他,这样他才能够使用“UserServiceImpl”,这就是Spring核心思想“控制反转”,也叫“依赖注入”,“依赖注入”也很好理解,Action需要使用UserServiceImpl干活,那么就是对UserServiceImpl产生了依赖,Spring把Acion需要依赖的UserServiceImpl注入(也就是“给”)给Action,这就是所谓的“依赖注入”。对Action而言,Action依赖什么东西,就请求Spring注入给他,对Spring而言,Action需要什么,Spring就主动注入给他。beans.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.0.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-3.0.xsd">
- <!-- 配置的bean所在包的位置 -->
- <context:component-scan base-package="com.mucfc" />
- </beans>
- package com.mucfc.anno;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- import com.mucfc.model.User;
- import com.mucfc.service.UserService;
- public class Test {
- public static void main(String[] args) {
- ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
- UserService service=(UserService)applicationContext.getBean("userService");
- User user1 = (User) applicationContext.getBean("user");
- User user2 = (User) applicationContext.getBean("user");
- user1.setName("小明");
- user1.setSex("男");
- user1.setAge(22);
- user2.setName("小红");
- user2.setSex("女");
- user2.setAge(18);
- service.add(user1);
- service.add(user2);
- }
- }
package com.mucfc.anno;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.mucfc.model.User;
import com.mucfc.service.UserService;
public class Test {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
UserService service=(UserService)applicationContext.getBean("userService");
User user1 = (User) applicationContext.getBean("user");
User user2 = (User) applicationContext.getBean("user");
user1.setName("小明");
user1.setSex("男");
user1.setAge(22);
user2.setName("小红");
user2.setSex("女");
user2.setAge(18);
service.add(user1);
service.add(user2);
}
}
结果:
当在组件类中使用了特定的注解之后,还需要在Spring的配置文件中声明 <context:component-scan>:
- base-package属性指定一个需要扫描的基类包,Spring容器将会扫描整个基类包里及其子包中的所有类
- 当需要扫描多个包时,可以使用逗号分隔
- 如果仅希望扫描特定的类而非基包下的所有类,可使用resource-pattern属性过滤特定的类,实例:
- <context:include-filter>子节点表示要包含的目标类
- <context:exclude-filter>子节点表示要排除在外的目标类
- <context:component-scan>下可以拥有若干个<context:include-filter>和<context:exclude-filter>子节点
- <context:include-filter>和<context:exclude-filter>子节点支持多种类型的过滤表