1. Spring 주석을 사용하여 속성 주입
1.1. 주석을 사용하기 전에 어떻게 속성을 주입했나요
클래스 구현:
class UserManagerImpl implements UserManager { private UserDao userDao; public void setUserDao(UserDao userDao) { this.userDao = userDao; } ... }
구성 파일 :
<bean id="userManagerImpl" class="com.kedacom.spring.annotation.service.UserManagerImpl"> <property name="userDao" ref="userDao" /> </bean> <bean id="userDao" class="com.kedacom.spring.annotation.persistence.UserDaoImpl"> <property name="sessionFactory" ref="mySessionFactory" /> </bean>
1.2. @Autowired 주석 도입(권장하지 않음, @Resource 사용 권장)
클래스 구현(멤버 변수 주석)
public class UserManagerImpl implements UserManager { @Autowired private UserDao userDao; ... }
또는 (메서드 표시)
UserManagerImpl implements UserManager { private UserDao userDao; @Autowired public void setUserDao(UserDao userDao) { this.userDao = userDao; } ... }
구성 파일
<bean id="userManagerImpl" class="com.kedacom.spring.annotation.service.UserManagerImpl" /> <bean id="userDao" class="com.kedacom.spring.annotation.persistence.UserDaoImpl"> <property name="sessionFactory" ref="mySessionFactory" /> </bean>
@Autowired는 멤버 변수, 메소드에 태그를 지정할 수 있으며 생성자에 주석이 추가됩니다. 자동 조립 작업을 완료합니다. 위의 두 가지 다른 구현에서는 @Autowired 주석 위치가 다릅니다. Spring이 userManagerImpl 빈을 초기화할 때 자동으로 userDao 속성을 어셈블합니다. 차이점은 다음과 같습니다. 첫 번째 구현에서 Spring은 UserDao 유형 중 하나만 직접 어셈블합니다. Bean은 userDao 멤버 변수에 할당됩니다. 두 번째 구현에서 Spring은 UserDao 유형의 유일한 Bean을 userDao 속성으로 어셈블하기 위해 setUserDao 메소드를 호출합니다.
1.3 @Autowired를 작동시키려면
class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />@Qualifier
구성 파일에 다음 코드를 추가해야 합니다. 🎜>@Autowired는 유형에 따라 자동으로 연결됩니다. 위의 예에서 Spring 컨텍스트에 UserDao 유형의 Bean이 두 개 이상 있으면 BeanCreationException이 발생합니다. Spring 컨텍스트에 UserDao 유형의 Bean이 없으면 BeanCreationException도 발생합니다. @Autowired와 함께 @Qualifier를 사용하면 이러한 문제를 해결할 수 있습니다.
1. 여러 개의 UserDao 인스턴스가 있을 수 있습니다
@Autowired public void setUserDao(@Qualifier("userDao") UserDao userDao) { this.userDao = userDao; }이러한 방식으로 Spring은 어셈블리를 위해 userDao라는 ID를 가진 Bean을 찾습니다.
2. UserDao 인스턴스가 존재하지 않을 수 있음
@Autowired(required = false) public void setUserDao(UserDao userDao) { this.userDao = userDao; }1.5.@Resource(JSR-250 표준 주석, Spring 고유의 @Autowired 주석 대신 사용을 권장함)
Spring은 자체 @Autowired 주석을 지원할 뿐만 아니라 @Resource, @PostConstruct 및 @PreDestroy와 같은 JSR-250 사양에 의해 정의된 여러 주석도 지원합니다.
@Resource의 기능은 @Autowired와 동일합니다. 단, @Autowired는 byType에 의해 자동으로 주입되고 @Resource는 기본적으로 byName에 의해 자동 주입됩니다. @Resource에는 name과 type이라는 두 가지 중요한 속성이 있습니다. Spring은 @Resource 주석의 name 속성을 bean의 이름으로 확인하고 type 속성은 bean의 유형으로 확인합니다. 따라서 name 속성을 사용하면 byName 자동 주입 전략이 사용되고, type 속성을 사용하면 byType 자동 주입 전략이 사용된다. name이나 type 속성이 모두 지정되지 않으면 byName 자동 주입 전략이 리플렉션 메커니즘을 통해 사용됩니다.
@Resource 어셈블리 순서
name이 지정되면 어셈블리 컨텍스트에서 일치하는 이름(id)을 가진 bean을 검색합니다. bean이 없으면 예외가 발생합니다.
이름도 유형도 아닌 경우 예외가 발생합니다. 지정되면 byName에 따라 자동으로 어셈블리가 수행됩니다(2 참조). 일치하는 항목이 있으면 기본 유형(UserDao)으로 대체됩니다.
1.6. @PostConstruct (JSR-250)
메서드에 @PostConstruct 주석을 추가하면 이 메서드는 Bean이 초기화된 후 Spring 컨테이너에 의해 실행됩니다(참고: Bean 초기화에는 Bean 인스턴스화 및 Bean 속성 어셈블이 포함됩니다) (종속성 주입)).
일반적인 애플리케이션 시나리오는 상위 클래스에 정의된 속성을 Bean에 삽입해야 하고 다음과 같이 상위 클래스의 속성이나 속성의 setter 메서드를 재정의할 수 없는 경우입니다.
public class UserDaoImpl extends HibernateDaoSupport implements UserDao { private SessionFactory mySessionFacotry; @Resource public void setMySessionFacotry(SessionFactory sessionFacotry) { this.mySessionFacotry = sessionFacotry; } @PostConstruct public void injectSessionFactory() { super.setSessionFactory(mySessionFacotry); } ... }
여기서 @PostConstruct를 통해 우리가 정의한 sessionFactory를 UserDaoImpl의 상위 클래스에 정의된 sessionFactory 비공개 속성에 삽입합니다(상위 클래스의 setSessionFactory 메서드는 최종적이며 재정의될 수 없습니다). super.getSessionFactory()를 호출하여 액세스합니다.
1.7.@PreDestroy(JSR-250)메서드에 @PreDestroy 주석을 추가하면 이 메서드는 Bean이 초기화된 후 Spring 컨테이너에 의해 실행됩니다. 현재 이를 사용해야 하는 시나리오가 없으므로 여기서는 시연하지 않겠습니다. 사용법은 @PostConstruct와 동일합니다.
1.8. bfe8fab089282832fed14fcb6f680c1e를 사용하여 구성 단순화
AutowiredAnnotationBeanPostProcessor 및 CommonAnnotationBeanPostProcessor는 이러한 주석 메타데이터를 처리하는 프로세서입니다. 그러나 Spring 구성 파일에서 이러한 Bean을 직접 정의하는 것은 서투른 작업입니다. Spring은 bfe8fab089282832fed14fcb6f680c1e:
<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-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <context:annotation-config /> </beans>
02b5e3170f8825be11991279b556a682将隐式地向Spring容器注册AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、 PersistenceAnnotationBeanPostProcessor以及RequiredAnnotationBeanPostProcessor这4个BeanPostProcessor。
2. 使用Spring注解完成Bean的定义
以上我们介绍了通过@Autowired或@Resource来实现在Bean中自动注入的功能,下面我们将介绍如何注解Bean,从而从XML配置文件中完全移除Bean定义的配置。
2.1. @Component(不推荐使用)、@Repository、@Service、@Controller
只需要在对应的类上加上一个@Component注解,就将该类定义为一个Bean了:
@Component public class UserDaoImpl extends HibernateDaoSupport implements UserDao { ... }
使用@Component注解定义的Bean,默认的名称(id)是小写开头的非限定类名。如这里定义的Bean名称就是userDaoImpl。你也可以指定Bean的名称:
@Component("userDao")
@Component是所有受Spring管理组件的通用形式,Spring还提供了更加细化的注解形式:@Repository、@Service、@Controller,它们分别对应存储层Bean,业务层Bean,和展示层Bean。目前版本(2.5)中,这些注解与@Component的语义是一样的,完全通用,在Spring以后的版本中可能会给它们追加更多的语义。所以,我们推荐使用@Repository、@Service、@Controller来替代@Component。
2.2. 使用5fac6a8af37bdf6785fe01c166cb3779让Bean定义注解工作起来
<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-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <context:component-scan base-package="com.kedacom.ksoa" /> </beans>
这里,所有通过60e23eb984d18edbb092da6b8f295aba元素定义Bean的配置内容已经被移除,仅需要添加一行5fac6a8af37bdf6785fe01c166cb3779配置就解决所有问题了——Spring XML配置文件得到了极致的简化(当然配置元数据还是需要的,只不过以注释形式存在罢了)。5fac6a8af37bdf6785fe01c166cb3779的base-package属性指定了需要扫描的类包,类包及其递归子包中所有的类都会被处理。
5fac6a8af37bdf6785fe01c166cb3779还允许定义过滤器将基包下的某些类纳入或排除。Spring支持以下4种类型的过滤方式:
过滤器类型 表达式范例 说明
注解 org.example.SomeAnnotation 将所有使用SomeAnnotation注解的类过滤出来
类名指定 org.example.SomeClass 过滤指定的类
正则表达式 com\.kedacom\.spring\.annotation\.web\..* 通过正则表达式过滤一些类
AspectJ表达式 org.example..*Service+ 通过AspectJ表达式过滤一些类
以正则表达式为例,我列举一个应用实例:
<context:component-scan base-package="com.casheen.spring.annotation"> <context:exclude-filter type="regex" expression="com\.casheen\.spring\.annotation\.web\..*" /> </context:component-scan>
值得注意的是5fac6a8af37bdf6785fe01c166cb3779配置项不但启用了对类包进行扫描以实施注释驱动Bean定义的功能,同时还启用了注释驱动自动注入的功能(即还隐式地在内部注册了AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor),因此当使用5fac6a8af37bdf6785fe01c166cb3779后,就可以将bfe8fab089282832fed14fcb6f680c1e移除了。
2.3. 使用@Scope来定义Bean的作用范围
在使用XML定义Bean时,我们可能还需要通过bean的scope属性来定义一个Bean的作用范围,我们同样可以通过@Scope注解来完成这项工作:
@Scope("session") @Component() public class UserSessionBean implements Serializable { ... }
3.在使用annotation之前定义三个bean之间的关系是这样的
package com.baobaotao; public class Office { private String officeNo =”001”; //省略 get/setter @Override public String toString() { return "officeNo:" + officeNo; } } ackage com.baobaotao; public class Car { private String brand; private double price; // 省略 get/setter @Override public String toString() { return "brand:" + brand + "," + "price:" + price; } } package com.baobaotao; public class Boss { private Car car; private Office office; // 省略 get/setter @Override public String toString() { return "car:" + car + "\n" + "office:" + office; } }
配置文件如下:
<?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-2.5.xsd"> <bean id="boss" class="com.baobaotao.Boss"> <property name="car" ref="car"/> <property name="office" ref="office" /> </bean> <bean id="office" class="com.baobaotao.Office"> <property name="officeNo" value="002"/> </bean> <bean id="car" class="com.baobaotao.Car" scope="singleton"> <property name="brand" value=" 红旗 CA72"/> <property name="price" value="2000"/> </bean> </beans>
测试文件如下:
import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class AnnoIoCTest { public static void main(String[] args) { String[] locations = {"beans.xml"}; ApplicationContext ctx = new ClassPathXmlApplicationContext(locations); Boss boss = (Boss) ctx.getBean("boss"); System.out.println(boss); } }
4.接下来我们可以使用autowired来注解,他可以对成员变量,方法及构造函数进行标准,完成自动装配的工作。
autoware来注解成员变量的用法
package com.baobaotao; import org.springframework.beans.factory.annotation.Autowired; public class Boss { @Autowired private Car car; @Autowired private Office office; … }
相应的配置文件如下:
<?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-2.5.xsd"> <!-- 该 BeanPostProcessor 将自动起作用,对标注 @Autowired 的 Bean 进行自动注入 --> <bean class="org.springframework.beans.factory.annotation. AutowiredAnnotationBeanPostProcessor"/> <!-- 移除 boss Bean 的属性注入配置的信息 --> <bean id="boss" class="com.baobaotao.Boss"/> <bean id="office" class="com.baobaotao.Office"> <property name="officeNo" value="001"/> </bean> <bean id="car" class="com.baobaotao.Car" scope="singleton"> <property name="brand" value=" 红旗 CA72"/> <property name="price" value="2000"/> </bean> </beans>
autoware也可以用在setter方法及构造函数上
package com.baobaotao; public class Boss { private Car car; private Office office; @Autowired public void setCar(Car car) { this.car = car; } @Autowired public void setOffice(Office office) { this.office = office; } … } package com.baobaotao; public class Boss { private Car car; private Office office; @Autowired public Boss(Car car ,Office office){ this.car = car; this.office = office ; } … }
当候选bean的数目为0时,我们可以使用@Autowired(required = false)来防止spring找不到bean时报错。
当有多个候选bean的时候,我们可以通过@Qualifier 注释指定注入 Bean 的名称。
@Autowired 和 @Qualifier 结合使用时,自动注入的策略就从 byType 转变成 byName 了。@Autowired 可以对成员变量、方法以及构造函数进行注释,而 @Qualifier 的标注对象是成员变量、方法入参、构造函数入参。正是由于注释对象的不同,所以 Spring 不将 @Autowired 和 @Qualifier 统一成一个注释类。
5.@resorce是按照名字来进行反射,他有两个参数,name和type,使用name即按照byname来映射,使用type即按照bytype来进行映射。
package com.baobaotao; import javax.annotation.Resource; public class Boss { // 自动注入类型为 Car 的 Bean @Resource private Car car; // 自动注入 bean 名称为 office 的 Bean @Resource(name = "office") private Office office; } @postconstructor和preDestory是用来注解类初始化后和销毁前的方法。 package com.baobaotao; import javax.annotation.Resource; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; public class Boss { @Resource private Car car; @Resource(name = "office") private Office office; @PostConstruct public void postConstruct1(){ System.out.println("postConstruct1"); } @PreDestroy public void preDestroy1(){ System.out.println("preDestroy1"); } … }
6.@compent可以直接定义bean,这样xml配置文件中就不需要配置bean了
package com.baobaotao; import org.springframework.stereotype.Component; @Component public class Car { … } package com.baobaotao; import org.springframework.stereotype.Component; @Component public class Office { private String officeNo = "001"; … } package com.baobaotao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Required; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; @Component("boss") public class Boss { @Autowired private Car car; @Autowired private Office office; … }
@Component 有一个可选的入参,用于指定 Bean 的名称,在 Boss 中,我们就将 Bean 名称定义为“boss”。一般情况下,Bean 都是 singleton 的,需要注入 Bean 的地方仅需要通过 byType 策略就可以自动注入了,所以大可不必指定 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-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <context:component-scan base-package="com.baobaotao"/> </beans>
7.@scope可以用来指定其目标
package com.baobaotao; import org.springframework.context.annotation.Scope; … @Scope("prototype") @Component("boss") public class Boss {
Spring 2.5 中除了提供 @Component 注释外,还定义了几个拥有特殊语义的注释,它们分别是:@Repository、@Service 和 @Controller。在目前的 Spring 版本中,这 3 个注释和 @Component 是等效的,但是从注释类的命名上,很容易看出这 3 个注释分别和持久层、业务层和控制层(Web 层)相对应。虽然目前这 3 个注释和 @Component 相比没有什么新意,但 Spring 将在以后的版本中为它们添加特殊的功能。所以,如果 Web 应用程序采用了经典的三层分层结构的话,最好在持久层、业务层和控制层分别采用 @Repository、@Service 和 @Controller 对分层中的类进行注释,而用 @Component 对那些比较中立的类进行注释。
更多详解Java的Spring框架中的注解的用法相关文章请关注PHP中文网!