SpringIOC(二)

255 阅读4分钟

生命周期回调

通过实现InitializingBean, DisposableBean接口

为了容器对bean的生命周期进行管理,可以实现Spring的InitializingBeanDisposableBean接口。通过重写afterPropertiesSet()destroy()方法使bean在初始化和销毁​​bean时执行某些操作。
@Repository
public class UserDaoImpl implements UserDao, InitializingBean, DisposableBean {    
    public UserDaoImpl(){        
        System.out.println("constructor");    
    }    
    @Override    
    public void afterPropertiesSet() throws Exception {        
        System.out.println("init");    
    }    
    @Override    
    public void destroy() throws Exception {        
        System.out.println("restroy");    
    }
}

xml

自定义方法,在xml中通过init-methodanddestroy-method属性指定初始化和销毁方法
<bean id="userDaoImpl" class="com.zjy.dao.UserDaoImpl" init-method="init"></bean>

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

注解

使用@PostConstruct @PreDestroy注解来标记初始化和销毁方法

@PostConstruct
public void init() {    
    System.out.println("init");
}

混合使用

为一个bean配置不同初始化方法的多个生命周期机制,则执行顺序

  1. 注解方法@PostConstruct
  2. 实现InitializingBean接口重写的afterPropertiesSet()
  3. 自定义的init-method的方法

销毁顺序相同。 注解->接口->自定义方法

使用过滤器自定义扫描

默认情况下,被`@Component,@Repository,@Service,@Controller,@Configuration`,或自定义的注解(自定义的注解包含`@Component`)标记的类会被检测到。但是,我们可以通过自定义过滤器来修改和扩展此行为。在`@ComponentScan`中添加属性includeFiltersexcludeFilters(或在XML的中配置)。每个过滤器元素都需要typeexpression属性。

下表描述了过滤选项:

通过@ComponentScan配置

@Configuration
@ComponentScan(basePackages = "org.example",
        includeFilters = @Filter(type = FilterType.REGEX, pattern = ".*Stub.*Repository"),
        excludeFilters = @Filter(Repository.class))
public class AppConfig {
    ...
}

XML配置

<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>

多个候选对象NoUniqueBeanDefinitionException错误解决

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: 
    No qualifying bean of type 'com.zjy.dao.UserDao' available: 
        expected single matching bean but found 2: userDaoImpl,userDaoImpl2 

原因:对象赋值的时候,本来是只需要把一个对象赋值给它,结果现在却发现了2个对象,于是Spring容器就不知道使用哪一个具体的子类了。

注解@Primary

由于按类型自动装配可能会导致多个候选对象,因此通常有必要对选择过程进行更多控制。@Primary指示当多个bean要自动装配到单值依赖项的候选对象时,应给予特定bean优先权。如果候选中恰好存在一个主bean,则它将成为自动装配的值。
@Repository
@Primary
public class UserDaoImpl implements UserDao{    
    public UserDaoImpl(){        
        System.out.println("constructor");    
    }
}

注解@Qualifier

@Primary当可以确定一个主要候选对象时,它是在几种情况下按类型使用自动装配的有效方法。当您需要更好地控制选择过程时,可以使用Spring的@Qualifier注释。您可以将限定符值与特定的参数相关联,从而缩小类型匹配的范围,以便为每个参数选择特定的bean。

public class UserService{    
    @Autowired    
    @Qualifier("userDaoImpl")    
    UserDao userDao;    
    public void getUser() {         
        System.out.println("userDao" + userDao.hashCode());    
    }
}

注解@Resource

通过byName注入

@Resource(name = "userDaoImpl")UserDao userDao;

环境配置

@profile 可以设置某一个配置文件在某一环境中生效,也可以设置摸一个bean在坏境中生效

@Repository
@Profile("dao2")
public class UserDaoImpl2 implements UserDao {}
@Repository
@Profile("dao")
public class UserDaoImpl implements UserDao{}

public static void main(String[] args) {    
    AnnotationConfigApplicationContext ac =            
        new AnnotationConfigApplicationContext();    
    ac.register(Spring.class);    
    ac.getEnvironment().setActiveProfiles("dao");    
    ac.refresh();    
    UserDao userDao = (UserDao) ac.getBean("userDaoImpl2");
}

启动时指定环境为dao,当我们获取userDaoImpl时,可以获取到。当获取userDaoImpl2时,由于@Profile("dao2"),标记环境为dao2,获取不到,报错

NoSuchBeanDefinitionException: No bean named 'userDaoImpl2' available

基于java的容器配置

Spring的新Java配置支持带@Configuration注释的类和带@Bean注释的方法。

@Bean

@Bean注释被用于指示一个方法实例,可以配置,并交由Spring IoC容器进行管理。对于那些熟悉Spring的XML配置的人来说,@Bean注释的作用与元素相同。通常与@Configuration一起使用。
@Bean
public MyService myService() {
    return new MyServiceImpl();}

相当于

<bean id="myService" class="com.acme.services.MyServiceImpl"/>

@Configuration

@Configuration表明其主要目的是作为Bean定义的来源。此外,@Configuration类允许通过调用@Bean同一类中的其他方法来定义Bean之间的依赖关系。@Configuration类是用meta注释的@Component,因此它们是组件扫描的候选对象。

使用javaConfig注入SqlSessionFactoryBean

先创建数据源

@Bean
public DataSource getDataSource() {    
    DriverManagerDataSource dataSource = new DriverManagerDataSource();    
    dataSource.setUsername("root");    
    dataSource.setPassword("123456");    
    dataSource.setDriverClassName("com.mysql.jdbc.Driver");    
    dataSource.setUrl("jdbc:mysql://localhost:3306/test");    
    return dataSource;
}

传入数据源创建SqlSessionFactoryBean

@Bean
public SqlSessionFactoryBean getSqlSessionFactory(DataSource dataSource) {    
    SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();    
    sqlSessionFactoryBean.setDataSource(dataSource);    
    return sqlSessionFactoryBean;
}

完整代码

@Configuration
public class Spring {    
    @Bean    
    public SqlSessionFactoryBean getSqlSessionFactory(DataSource dataSource) {        
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();        
        sqlSessionFactoryBean.setDataSource(dataSource);        
        return sqlSessionFactoryBean;   
    }    
    @Bean    
    public DataSource getDataSource() {        
        DriverManagerDataSource dataSource = new DriverManagerDataSource();        
        dataSource.setUsername("root");        
        dataSource.setPassword("123456");        
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");        
        dataSource.setUrl("jdbc:mysql://localhost:3306/test");        
        return dataSource;    
    }
}

结语

至于没写到的,可能涉及到源码部分,会在学习源码的时候在写。也可能是我漏掉了。

想更透彻的理解spring,源码和官网必不可少。