那些年我们一起着迷的Spring: 基于java的容器注解(七)

基于java的容器注解

@Bean标识一个用于配置和初始化一个由Spring IOC容器管理的新对象的方法,类似于XML配置文件的<bean> </bean>
可以在Spring的@Component注解的类中使用@Bean注解任何方法(仅仅是可以)
通常是使用的是@Configuration

bean的配置项可以通过注释的方式

@Bean(initMethod = "init") 
@Bean(destroyMethod = "destroy")
package com.zjx.bean;

public class StringStore implements Store {
    
    
public void init(){
    
    
    System.out.println("this is init...");
}
public void destroy(){
    
    
    System.out.println("this is destroy");
}
package com.zjx.bean;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class StoreConfig {
    
    
    @Bean(initMethod="init",destroyMethod="destroy")
    public Store stringStore(){
    
    
        return new StringStore();
    }

}

资源文件的读取方式

<context:annotation-config></context:annotation-config>
<context:property-placeholder location="classpath:/Spring/src/jdbc.properties"/>
<bean class="com.Appconfig"></bean>
<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="url" value="${jdbc.url}"></property>
    <property name="username" value="${jdbc.username}"></property>
    <property name="password" value="${jdbc.password}"></property>
</bean>

或者在类中写注释:

package com.zjx.properties;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.jdbc.datasource.DriverManagerDataSource;

@Configuration
@ImportResource("classpath:/Spring/src/jdbc.properties")
public class AppConfig {
    
    
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String userName;
    @Value("${jdbc.password}")
    private String passWord;

    public DataSource dataSource(){
    
    
        return new DriverManagerDataSource(url, userName, passWord);
    }
}

@Scope

默认@Bean是单例的
@Scope里边还有另外一个属性proxyMode,即采用哪一种的代理方式

@Bean(name = "stringStore")
//基于接口interface,基于类的TARGET_CLASS。
@Scope(value="prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
public Store stringStore() {
    
    
    return new StringStore();
}

基于泛型的自动装配

@Configuration
public class MyConfiguration{
    
    
    @Bean
    public StringStore stringStore(){
    
    
        return new StringStore();
    }
    @Bean
    public IntegerStore integerStore(){
    
    
        return new IntegerStore();
    }
}
@Autowired
private Store<String> s1;

@Autowired
private Store<Integer> s2;

在进行@Autowired自动装配的时候,两个Store s1和s2,第一个是String第二个是Integer。也就是说通过这种泛型的方式来指定s1和s2分别对应哪一个bean。s1泛型里边指定的是String,那么s1对应的应该是上边的StringStore,s2对应IntegerStore。

//在一个集合里边的Store对象泛型指定的都是Integer类型的
@Autowired
private List<Store<Integer>> s;

将之前的一些类进行修改 接口里指定T泛型:public interface Store<T> {}

public class StringStore implements Store<String> {
    
    

    public void init() {
    
    
        System.out.println("This is init.");
    }

    public void destroy() {
    
    
        System.out.println("This is destroy.");
    }
}

public class IntegerStore implements Store<Integer> {
    
    }

在StoreConfig类中进行声明

@Autowired
private Store<String> s1;

@Autowired
private Store<Integer> s2;

@Bean
public StringStore stringStore() {
    
    
    return new StringStore();
}

@Bean
public IntegerStore integerStore() {
    
    
    return new IntegerStore();
}

@Bean(name = "stringStoreTest")
// public StringStore stringStoreTest() {
    
    
public Store stringStoreTest() {
    
    
    System.out.println("s1 : " + s1.getClass().getName());
    System.out.println("s2 : " + s2.getClass().getName());
    return new StringStore();
}

Autowire扩展内容,关于自定义qualifier注解

CustomeAutowireConfigurer是BeanFactoryPostProcessor的子类,通过它可以注册自己的qualifier注解类型(即使没有使用Spring的@Qualifier注解)

<bean id="customAutowireConfigurer" class="org.springframework.beans.factory.annotation.CustomAutowireConfigurer">
    <property name="customQualifierTypes">
        <set>
            <value>example.CustomQualifier</value>
        </set>
    </property>
</bean>

class指定类,这个类中有个属性customQualifierTypes,具体有哪些类型,我们可以把自己定义的类型放在里边,注意这里是Set,也就是说我们可以放很多个。

AutowireCandidateResolver

决定自动装配的候选者:

  • 每个bean定义的autowire-candidate值
  • 任何<bean/>中的default-autowire-candidates
  • @Qualifier注解及使用CustomAutowireConfigurer的自定义类型。
    很少会使用到

对JSR的支持

@PostConstruct and @PreDestroy

CommonAnnotationBeanPostProcessor不仅能识别JSR-250中的生命周期注解@Resource,在Spring2.5中引入支持初始化回调和销毁回调,前提是CommonAnnotationBeanPostProcessor是Spring的ApplicationContext中注册的

public class CachingMovieLister{
    
    
    @PostConstruct
    public void populateMovieCache(){
    
    
        //...
    }
    @PreDestroy
    public void clearMovieCache(){
    
    
        //...
    }
}
//在初始化和销毁之前都会调用这两个注解所注解的方法。

注解提供的名字被解析成为一个bean的名称,这是由ApplicationContext中的CommonAnnotationBeanPostProcessor发现并处理的

示例:

@Repository
public class JsrDAO {
    
    
    public void save() {
    
    
        System.out.println("JsrDAO invoked.");
    }
}

@Service
public class JsrService{
    
    

//没有DAO赋值,会出现空指针异常。
//一种是在成员变量上使用@Resource注解,还有一种是生成set方法,在这个方法上使用@Resource注解。
 	 @Resource
    private JsrDAO jsrDAO;//把DAO的实例注入到当前的实例中来
/*或
@Resource
public void setJsrDAO(JsrDAO jsrDAO) {
    this.jsrDAO = jsrDAO;
}*/

    public void save(){
    
    
     System.out.println("JsrServie save");
        jarDAO.save();
    }
	
	@PostConstruct
	public void init() {
    
    
	    System.out.println("JsrServie init.");
	}	
	@PreDestroy
	public void destroy() {
    
    
	    System.out.println("JsrServie destroy.");
	}
}
//单元测试
@Test
public void testSave() {
    
    
    JsrServie service = getBean("jsrServie");
    service.save();
}

先输出JsrServie init.,再输出save()方法调用,最后输出JsrServie destroy.

使用JSR330标准注释

从Spring3.0开始支持JSR330标准注解(依赖注入注解),其扫描方式与Spring注解一致
使用JSR330需要依赖javax.inject包
使用Maven引入方式

<dependency>
    <groupId>javax.inject</groupId>
    <artifactId>javax.inject</artifactId>
    <version>1.0</version>
</dependency>

@Inject

@Inject等效于@Autowired,可以使用于类、属性、方法、构造器

import javax.inject.Inject

public class SimpleMovieLister{
    
    

    private MovieFinder movieFinder;

    @Inject
    public void setMovieFinder(MovieFinder movieFinder){
    
    
        this.movieFinder=movieFinder;
    }
}

@Named

如果想使用特定名称进行依赖注入,使用@Named。也就是说同一种类型的bean在IOC容器中有多个的话,如果想使用特定的那个bean,就可以使用这个注解。
@Named和@Component是等效的

//注解在类上
@Named("movieListener")
public class SimpleMovieLister{
    
    
    private MovieFinder movieFinder;
    @Inject
    public void setMovieFinder(MovieFinder movieFinder){
    
    
        this.movieFinder=movieFinder;
    }
}
//用来指定某一个名称的bean。和Qualifier有点类似
public class SimpleMovieLister{
    
    
    private MovieFinder movieFinder;
    @Inject
    public void setMovieFinder(@Named("main")MovieFinder movieFinder){
    
    
        this.movieFinder=movieFinder;
    }
}

在之前的例子中可以进行修改
JsrService类上的@Service可以改为Named,里边在成员变量和set方法上的@Resource注解可以改为@Inject,输出不变。

//  @Resource
    @Inject
    public void setJsrDAO(@Named("jsrDAO") JsrDAO jsrDAO) {
    
    
        this.jsrDAO = jsrDAO;
    }

这里还可以加上(@Named(“jsrDAO”)。有什么作用?
加入这个JsrDAO类在当前的IOC容器中有两个bean,或者这么说,加入这是一个接口,它有两个实现类,都注入到了当前的IOC容器中,就像前边例子中的StringStore和IntegerStore,那么就可以通过Named引用到底是哪一个。

参考:
Spring入门(Spring对JSR支持的说明)
https://blog.csdn.net/qq_36206746/article/details/78141904
https://blog.csdn.net/kang82651204/article/category/6070639

猜你喜欢

转载自blog.csdn.net/eluanshi12/article/details/96875294