这篇讲解Bean管理的注解实现及例子
主要内容有:
- Classpath扫描与组件管理
- 类的自动检测和注册Bean
- <context:annotation-config/>
- @Component、@Repository、@Service、@Controller
- @required
- @Autowired
- @Qualifier
- @Resource
一、classpath扫描与组件管理
- 从Spring3.0开始,SpringJavaConfig项目提供了很多特性,包括使用Java而不是xml定义bean,比如@Configuration、@Bean、@Import、@DependsOn等等。之所以使用注解,主要是为了降低使用xml设置bean的工作量。
- @Component是一个通用注解,可用于任何bean;
- @Repository、@Service、@Controller是更有针对性的注解,也是@Component的子注解:
- @Repository通常用于注解Dao类,即持久层
- @Service通常用于注解Service类,即服务层
- @Controller通常用于注解Controller类,即控制层(MVC)
元注解(Meta-annotations)
- 许多Spring提供的注解可以作为自己的代码,即“元数据注解”,元注解是一个简单的注解,可以应用到另一个注解。
- 除了value(),元注解还可以有其他属性,允许自定义
关于注解可以参考,我之前写的一篇文章:理解java注解
类的自动检测及bean的注册
- Spring可以自动检测类并注册bean到ApplicationContext中。其中注解可以注册在类上也可以注册在方法、变量上。
<context:annotation-config/>:
- 通过在基于XML的Spring配置如下标签(请注意包含上下文命名空间)
- <context:annotation-config/>仅会查找在同一个ApplicaitonContext中的bean注解
- 可以扫描已经注册在IoC容器中的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,需要下面内容
<?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="org.example"/>
</beans>
- <context:component-scan>可以扫描基于类的注解
- <context:component-scan>包含<context:annotation-config>,通常在使用<context:component-scan>后,就不再使用<context:annotation-config>
- AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor也会被包含进来
使用过滤器进行自定义扫描
- 默认情况下,类被自动发现并注册bean的条件是:使用@Component,@Repository,@Service,@Controller注解或者使用@Component的自定义注解
- 可以通过过滤器修改上面的行为,如,下面的例子的xml配置忽略所有的@Repository注解并用“Stub”代替。
<beans>
<context:component-scan base-package="org.example">
<context:include-filter type="regex"
expression=".*Stub.*Repository"/>
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Repository"/>
</context:component-scan>
</beans>
- 还可以使用use-default-filters="false"禁用自动发现与注册。
过滤类别 | 示例 | 说明 |
---|---|---|
annotation | org.example.SomeAnnotation | 所有标注了SomeAnnotation的类。该类型采用目标类是否标注了某个注解进行过滤 |
assignable | org.example.SomeClass | 所有继承或扩展SomeClass的类。该类型采用目标类是否继承或扩展某个特定类进行过滤 |
aspectj | org.example..*Service+ | 所有类名以Service结束的类及继承或扩展了它们的类。该类型采用AspectJ表达式进行过滤 |
regex | org\.example\.Default.* | 所有org.example.Default包下的类。该类型采用正则表达式根据类的类名进行过滤 |
custom | org.example.MyTypeFiflter | 采用MyTypeFiflter通过代码的方式定义过滤规则。该类必须实现org.springframework.core.type.TypeFiflter接口 |
理解spring注解,参考:JAVA 注解的学习和对Spring注解的理解
定义BeanName(IoC容器总的beanId)
- 扫描过程中组件被自动检测,那么Bean名称是由BeanNameGenerator生成的(@Component、@repository、@Service、@Controller都会有个name属性用于显式设置Bean Name)
例如:
显式设置beanName,也就是直接设置IoC文件中的beanId:
@Service("TestResourceService")
public class TestResource implements ApplicationContextAware {
//……
}
不显式设置beanName的话,BeanNameGenerator会根据一定规则生成beanName,即类名首字母小写:
@Service
public class TestResource implements ApplicationContextAware {
//……
}
- 可自定义bean命名策略,实现BeanNameGenerator接口,并一定要包含一个无参数构造器。
记得在IoC注册,例如:
<beans>
<context:component-scan base-package="org.example"
name-generator="org.example.MyNameGenerator"/>
</beans>
作用域(Scope)
- 通常情况下自动查找的Spring组件,其scope是singleton,Spring2.5提供了一个标识scope的注解@Scope。
@Scope("prototype")
@Service("TestResourceService")
public class TestResource implements ApplicationContextAware {
//……
}
- 也可以自定义scope策略,实现ScopeMetadataResolver接口并提供一个无参构造器。
<beans>
<context:component-scan base-package="org.example"
scope-resolver="org.example.MyScopeResolver"/>
</beans>
代理方式
- 可以使用scoped-proxy属性指定代理,有三个值可选:no、interfaces、targetClass
<beans>
<context:component-scan base-package="org.example"
scope-proxy="interfaces"/>
</beans>
写个示例:
- IoC容器中添加<context:component-scan>:
<?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="test9"></context:component-scan>
</beans>
- 在test9包下新增一个BeanAnnotation类并使用@Component注解:
package test9;
import org.springframework.stereotype.Component;
@Component
public class BeanAnnotation {
public void say(String str) {
System.out.println("BeanAnnotation:" + str);
}
}
- junit测试:
@Test
public void test9(){
BeanAnnotation beanAnnotation=super.getBean("beanAnnotation");
beanAnnotation.say("类的自动检测及bean的注册");
}
- 显式指定beanName:
@Component("myBeanAnnotation")
public class BeanAnnotation {
public void say(String str) {
System.out.println("BeanAnnotation:" + str);
}
}
- junit测试:
@Test
public void test9(){
BeanAnnotation beanAnnotation=super.getBean("myBeanAnnotation");
beanAnnotation.say("类的自动检测及bean的注册");
}
- 在类中增加@Scope注解和showHashCode()方法
@Scope("prototype")
@Component("myBeanAnnotation")
public class BeanAnnotation {
public void say(String str) {
System.out.println("BeanAnnotation:" + str);
}
public void showHashCode(){
System.out.println("HashCode:" + hashCode());
}
}
- junit测试:
@Test
public void test9(){
BeanAnnotation beanAnnotation=super.getBean("myBeanAnnotation");
beanAnnotation.showHashCode();
BeanAnnotation beanAnnotation2=super.getBean("myBeanAnnotation");
beanAnnotation2.showHashCode();
}
-
结果如下图,使用@Scope注解修改作用域成功~:
将@Scope的值去掉,还原它本身的样子
@Scope
@Component("myBeanAnnotation")
public class BeanAnnotation {
public void say(String str) {
System.out.println("BeanAnnotation:" + str);
}
public void showHashCode(){
System.out.println("HashCode:" + hashCode());
}
}
-
再次执行junit测试,结果如图:
@Required
- @Required注解适用于bean属性的setter方法。
- 这个注解仅仅表示,受影响的bean属性必须在配置时被填充,通过在bean的定义或通过自动装配的一个明确属性值。
@Component("myBeanAnnotation")
public class BeanAnnotation {
private TestResource testResource;
@Required
public void setTestResource(TestResource testResource) {
this.testResource = testResource;
}
}
@Autowired
- 可以将@Autowired注解理解为“传统”的setter方法。
@Component("myBeanAnnotation")
public class BeanAnnotation {
private TestResource testResource;
@Autowired
public void setTestResource(TestResource testResource) {
this.testResource = testResource;
}
- 可用于构造器或成员变量
@Component("myBeanAnnotation")
public class BeanAnnotation {
@Autowired
private TestResource testResource;
private AutoWiringDao autoWiringDao;
@Autowired
public BeanAnnotation(AutoWiringDao autoWiringDao) {
}
}
- 默认情况下,如果因找不到合适的bean将会导致autowiring失败抛出异常,可以通过下面的方式避免。
@Component("myBeanAnnotation")
public class BeanAnnotation {
private TestResource testResource;
@Autowired(required = false)
public void setTestResource(TestResource testResource) {
this.testResource = testResource;
}
}
- 每个类只能有一个构造器被标记为required=true
- @Autowired的必要属性,建议使用@Required注解
关于Spring自动装配可以参考:spring的自动装配
关于Autowired自动装配的示例:
- service层实现类:
@Service
public class TestServiceImpl implements TestService {
//@Autowired用于成员变量(不需要写setter方法了)
@Autowired
private TestDao testDao;
@Override
public void save(String str) {
//模拟业务操作
System.out.println("TestServiceImpl接收参数:" + str);
str = str + ":" + this.hashCode();
testDao.save(str);
}
}
- junit测试:
@Test
public void test10() {
TestServiceImpl testService = super.getBean("testServiceImpl");
testService.save("this is autowired");
}
-
结果:
- 修改service层,将@Autowire设置在setTestDao()方法上:
@Service
public class TestServiceImpl implements TestService {
private TestDao testDao;
//@Autowired用于setter方法和用于变量是一个意思
@Autowired
public void setTestDao(TestDao testDao) {
this.testDao = testDao;
}
@Override
public void save(String str) {
//模拟业务操作
System.out.println("TestServiceImpl接收参数:" + str);
str = str + ":" + this.hashCode();
testDao.save(str);
}
}
-
结果:
修改service层,将@Autowire设置在构造器方法上:
@Service
public class TestServiceImpl implements TestService {
private TestDao testDao;
//@Autowired用构造
@Autowired
public TestServiceImpl(TestDao testDao) {
this.testDao = testDao;
}
@Override
public void save(String str) {
//模拟业务操作
System.out.println("TestServiceImpl接收参数:" + str);
str = str + ":" + this.hashCode();
testDao.save(str);
}
}
-
结果:
继续学习@Autowired
- 可以使用@Autowired注解那些众所周知的解析依赖性接口。比如:BeanFactory、ApplicationContext、Environment、resourceLoader、ApplicationEventPublisher、MessageSource。
- 可以给集合添加@Autowired注解,例如List<interface>,ApplicationContext中所有符合条件的此接口的实现类(bean)会传入到List中。
@Autowired
private List<BeanInterface> list;
- 可以给Map<String,Interface>添加@Autowired注解,例如:Map<String,BeanInterface>,在ApplicationContext中符合条件的此接口实现类会自动被加入到map中。其中key为beanId,Value是bean本身。
@Autowired
private Map<String,BeanInterface> map;
- 如果希望集合有序,可以让bean实现org.springframework.core.Ordered接口或使用@Order注解
- @Antowired是由Spring BeanPostProcessor处理的,所以不能在自己的BeanPostProcessor或BeanFactoryPostProcessor类型应用这些注解,这些类型必须通过xml或者Spring的@Bean注解加载。
数组及Map的自动注入例子
- 准备工作
- 新建一个接口
package test11;
/**
* Created by amber on 2017/6/15.
*/
public interface BeanInterface {
}
* 新建两个它的实现类BeanImplOne 、BeanImplTwo 并添加通用注解@Component
package test11;
import org.springframework.stereotype.Component;
/**
* Created by amber on 2017/6/15.
*/
@Component
public class BeanImplOne implements BeanInterface {
}
package test11;
import org.springframework.stereotype.Component;
/**
* Created by amber on 2017/6/15.
*/
@Component
public class BeanImplTwo implements BeanInterface {
}
- 新建一个调用类BeanInvoker 在其类上添加了注解@Component,两个属性 List<BeanInterface>和Map<String,BeanInterface>也添加了@Autowired注解。
package test11;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
/**
* Created by amber on 2017/6/15.
*/
@Component
public class BeanInvoker {
@Autowired
private List<BeanInterface> list;
@Autowired
private Map<String,BeanInterface> map;
public void say(){
if(list!=null){
System.out.println("list is not null! ");
for(BeanInterface item : list){
System.out.println("className: "+item.getClass().getName());
}
}else {
System.out.println("list is null! ");
}
if(map!=null){
System.out.println("map is not null! ");
for(Map.Entry item : map.entrySet()){
System.out.println("key: "+item.getKey()+ " className: "+item.getValue().getClass().getName());
}
}else {
System.out.println("map is null! ");
}
}
}
- 测试函数:
@Test
public void test11() {
BeanInvoker invoker=super.getBean("beanInvoker");
invoker.say();
}
-
结果:
- 增加集合类型的排序,在两个实现类上使用@Order
package test11;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
* Created by amber on 2017/6/15.
*/
@Order(2)
@Component
public class BeanImplOne implements BeanInterface {
}
package test11;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
* Created by amber on 2017/6/15.
*/
@Order(1)
@Component
public class BeanImplTwo implements BeanInterface {
}
经过排序,BeanImplTwo 就对照@Order(1),先被加入到list中了。
Qualifier
- 因为@Autowired默认是按类型查找注入的,所以可能多个bean实例的情况,这时可以使用Spring的Qualifier注解(变成按名称查找)缩小范围或指定唯一,也可以用于指定单独的构造器参数或方法参数。
- 可用于注解集合类型变量。
- 如果通过名字进行注解注入,主要使用的不是@Autowired(即使在技术上能够通过@Qualifier指定bean的名字),替代方式是使用JSR-250@Resource注解,它是通过其独特的名称来定义来识别特定的目标(这是一个与所声明类型无关的匹配过程)。
- 因语义的差异,集合或Map类型的bean,无法通过@Autowired来注入,因为没有类型匹配到这样的bean,为这些bean使用@Resource注解,通过唯一名称引用集合或者Map的bean。
- @Autowired适用于局部变量、构造、多参数方法这些允许在参数级别使用@Qualifier注解缩小范围的情况。
- @Resource适用于成员变量、只有一个参数的setter方法,所以在目标是构造器或一个多参数的方法时,最好的方式是使用@Qualifier。
在xml配置文件中使用qualifier ,就相当于beanid:
<bean class="test11.BeanImplOne">
<qualifier value="main"/>
</bean>
上一个测试得知BeanInterface 有两个实现类,我现在使用@Qualifier注解指定只注入其中一个:
@Autowired
@Qualifier("beanImplOne")
private BeanInterface beanInterface;
public void say(){
if(beanInterface!=null){
System.out.println("name: "+beanInterface.getClass().getName());
}else {
System.out.println("beanInterface is null! ");
}
}
结果:
基于Java容器的注解@Bean
- @Bean标识一个用于配置和初始化一个由ApringIoC容器管理的新对象的方法,类似于xml配置文件的<bean/>。
- 可以在Spring的@Componet注解的类中使用@Bean注解任何方法(仅仅是可以)。
- 通常和@Bean结合使用的是@Configuration。
- @Bean在方法上注解,方法名是bean默认的id。
示例:
- 创建一个Store接口:
package test12;
/**
* Created by amber on 2017/6/15.
*/
public interface Store {
}
- 创建一个它的是实现类,StringStore:
package test12;
/**
* Created by amber on 2017/6/15.
*/
public class StringStore implements Store {
}
- 创建StringConfig
package test12;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Created by amber on 2017/6/15.
*/
@Configuration
public class StringConfig {
@Bean
public Store getStringStore(){
return new StringStore();
}
}
- 测试方法:
@Test
public void test12() {
Store store=super.getBean("getStringStore");
System.out.println("store name: "+store.getClass().getName());
}
结果:
- 指定@Bean(name="xx")
package test12;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Created by amber on 2017/6/15.
*/
@Configuration
public class StringConfig {
@Bean(name = "stringStore")
public Store getStringStore(){
return new StringStore();
}
}
@Test
public void test12() {
Store store=super.getBean("stringStore");
System.out.println("store name: "+store.getClass().getName());
}
结果:
- 指定这个bean的init和destroy方法
@Bean(name = "stringStore",initMethod="init",destroyMethod = "destroy")
public Store getStringStore(){
return new StringStore();
}
StringStore类添加init和destroy方法:
package test12;
/**
* Created by amber on 2017/6/15.
*/
public class StringStore implements Store {
public void init(){
System.out.println("StringStore初始化");
}
public void destroy(){
System.out.println("StringStore销毁");
}
}
运行结果:
基于Java容器的注解@ImportResource和@Value注解进行资源文件读取并把结果注入到对应属性
- 使用xml进行配置:
- 通过<context:property-placeholder location="classpath:jdbc.properties"/>加载配置文件
- <property name="url" value="${db.url}"></property>通过EL表达式获取对应属性的值
applicationContext.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: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="test12"></context:component-scan>
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="url" value="${db.url}"></property>
<property name="username" value="${db.username}"></property>
<property name="password" value="${db.password}"></property>
</bean>
</beans>
jdbc.properties文件:
db.driverLocation=I:/IdeaProjects/mysql-connector-java-5.1.6-bin.jar
db.driverClassName=com.mysql.jdbc.Driver
db.url=jdbc:mysql://127.0.0.1:3306/ambermall?characterEncoding=utf-8
db.username=root
db.password=amber
- 使用注解进行配置:
创建MyDriverManager类:
package test12;
/**
* Created by amber on 2017/6/16.
*/
public class MyDriverManager {
public MyDriverManager(){}
public MyDriverManager(String url,String userName,String password){
System.out.println("url: "+url+"\nuserName: "+userName+"\npassword: "+password);
}
}
修改之前的StringConfig类如下:
因为我加载的是.properties文件,所以注解使用@PropertySource。如果加载xml文件,请使用@ImportResource
package test12;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.context.annotation.PropertySource;
/**
* Created by amber on 2017/6/15.
*/
@Configuration
@PropertySource("classpath:jdbc.properties")
public class StringConfig {
@Value("${db.url}")
private String url;
@Value("${db.username}")
private String userName;
@Value("${db.password}")
private String password;
@Bean
public MyDriverManager myDriverManager(){
return new MyDriverManager(url,userName,password);
}
}
测试方法:
@Test
public void test12() {
MyDriverManager manager = super.getBean("myDriverManager");
if(manager!=null)
System.out.println(manager.getClass().getName());
}
结果:
@Bean和@Scope
- 使用@Bean注解,默认是单例模式的。可以通过作用域注解@Scope,更改其他模式。
- @Scope的取值是:singleton、prototype、request、session、global session。
下面示例:
- 更改StringConfig类
package test12;
import org.springframework.context.annotation.*;
/**
* Created by amber on 2017/6/15.
*/
@Configuration
public class StringConfig {
@Bean(name = "stringStore",initMethod = "init",destroyMethod = "destroy")
@Scope("prototype")
public Store stringStore() {
return new StringStore();
}
}
- 测试方法:
@Test
public void test12() {
for(int i=0;i<2;i++){
StringStore store = super.getBean("stringStore");
System.out.println(store.hashCode());
}
}
- 结果:细心的小伙伴可能发现,多例之后,没有执行destroy的方法了,那是因为多例模式,每产生一个实例在使用完成后,都会自动被JVM垃圾回收器回收。
基于泛型的自动装配
示例:
- 修改Store接口:
package test12;
/**
* Created by amber on 2017/6/15.
*/
public interface Store<T>{
}
- 修改实现类StringStore :
package test12;
/**
* Created by amber on 2017/6/15.
*/
public class StringStore implements Store<String> {
}
增加IntegerStore:
package test12;
/**
* Created by amber on 2017/6/16.
*/
public class IntegerStore implements Store<Integer> {
}
- 更改StringConfig 类:
package test12;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.*;
/**
* Created by amber on 2017/6/15.
*/
@Configuration
public class StringConfig {
@Autowired
private StringStore s1;
@Autowired
private IntegerStore s2;
@Bean
public Store store() {
System.out.println("s1: "+s1.getClass().getName());
System.out.println("s2: "+s2.getClass().getName());
return new StringStore();
}
@Bean
public StringStore stringStore(){
return new StringStore();
}
@Bean
public IntegerStore integerStore(){
return new IntegerStore();
}
}
- 测试
@Test
public void test12() {
super.getBean("store");
}
-
结果:
CustomAutowireConfigurer
- CustomAutowireConfigurer是一个BeanFactoryPostProcessor子类,这个后置处理器可以注册开发者自己的限定符注解,让开发者的注解不依赖于Spring限定符注解。
- 通过CustomAutowireConfigurer可以注册自己的qualifier注解类型(即使没有使用Spring的@qualifier注解)
<bean id="customAutowireConfigurer"
class="org.springframework.beans.factory.annotation.CustomAutowireConfigurer">
<property name="customQualifierTypes">
<set>
<value>example.CustomQualifier</value>
</set>
</property>
</bean>
AutowireCandidateResolver用来处理customQualifierTypes的,通过以下的几种方式来决定自动装载的候选Bean:
* Bean定义中的autowire-candidate的值
* 任何<beans/>标签中定义的default-autowire-candidates的值
* @Qualifier注解和任何在CustomAutowireConfigurer中定义的自定义的限定符注解
* 当多个Bean限定为自动装载的候选时, 前文中提到的primary属性是优先考虑的。
@Resource
- Spring还支持使用JSR-250@Resource注解的变量或setter方法,这是一种在java EE 5和6的通用方式,Spring管理的对象也支持这种模式。
- @Resource有一个name属性,并且默认Spring解释该值,作为被注入bean的名称。
- 如果没有显式地指定@Resource的name,默认的名称是从属性名或者setter方法得出。
- 注解提供的名字,被解析为一个bean名称,这是由ApplicationContext中的CommonAnnotationBeanPostProcesser发现并处理的。
@PostConstruct 和 @PreDestroy
- CommonAnnotationBeanPostProcesser类不仅能识别JSR-250中的生命周期注解@Resource,在Spring2.5中引入支持初始化回调(@PostConstruct)和销毁回调( @PreDestroy),前提是CommonAnnotationBeanPostProcesser类是Spring的ApplicationContext中注册的。
下面示例:
- 创建JsrDao 类:
package test13;
import org.springframework.stereotype.Repository;
/**
* Created by amber on 2017/6/16.
*/
@Repository
public class JsrDao {
public void save(){
System.out.println("JsrDao invoked");
}
}
- 创建JsrService 类:
package test13;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* Created by amber on 2017/6/16.
*/
@Service
public class JsrService {
//@Resource注解在成员变量上或者方法上都是一样的效果,二者选其一即可,此处为了展示才都写上了。此处也可以替换成@Autowired,效果也是一样的
@Resource
private JsrDao jsrDao;
//@Resource注解在成员变量上或者方法上都是一样的效果,二者选其一即可,此处为了展示才都写上了。此处也可以替换成@Autowired,效果也是一样的
@Resource
public void setJsrDao(JsrDao jsrDao) {
this.jsrDao = jsrDao;
}
public void save(){
jsrDao.save();
}
}
- 测试:
@Test
public void test13() {
JsrService jsrService=super.getBean("jsrService");
jsrService.save();
}
-
结果:
- 在JsrService 中添加@PostConstruct 和 @PreDestroy
package test13;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
/**
* Created by amber on 2017/6/16.
*/
@Service
public class JsrService {
@Resource
private JsrDao jsrDao;
@Resource
public void setJsrDao(JsrDao jsrDao) {
this.jsrDao = jsrDao;
}
@PreDestroy //销毁回调
public void destroy(){
System.out.println("我是销毁回调");
}
@PostConstruct //初始化回调
public void init(){
System.out.println("我是初始化回调");
}
public void save(){
jsrDao.save();
}
}
-
结果:
使用JSR330标准注解
- 从Spring3.0开始支持JSR330标准注解(依赖注入注解),其扫描方式与Spring注解一致。
- 使用JSR330需要依赖javax.inject包
- 使用Maven引入方式
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
@Inject
- @Inject等效于@Autowired,可以使用于类、属性、方法、构造器。
@Named
- 如果想使用特定名称进行依赖注入,使用@Named。
- @Named与@Component是等效的。
- @Named与@Qualifier类似。
下面示例:
- 修改JSRService类的注解@Service改成@Named
package test13;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.inject.Inject;
import javax.inject.Named;
/**
* Created by amber on 2017/6/16.
*/
@Named
public class JsrService {
@Inject
private JsrDao jsrDao;
@Inject
public void setJsrDao(JsrDao jsrDao) {
this.jsrDao = jsrDao;
}
@PreDestroy //销毁回调
public void destroy(){
System.out.println("我是销毁回调");
}
@PostConstruct //初始化回调
public void init(){
System.out.println("我是初始化回调");
}
public void save(){
jsrDao.save();
}
}
-
运行结果: