生命周期回调
通过实现InitializingBean, DisposableBean接口
为了容器对bean的生命周期进行管理,可以实现Spring的InitializingBean和DisposableBean接口。通过重写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配置不同初始化方法的多个生命周期机制,则执行顺序
- 注解方法
@PostConstruct - 实现
InitializingBean接口重写的afterPropertiesSet() - 自定义的
init-method的方法
销毁顺序相同。 注解->接口->自定义方法
使用过滤器自定义扫描
默认情况下,被`@Component,@Repository,@Service,@Controller,@Configuration`,或自定义的注解(自定义的注解包含`@Component`)标记的类会被检测到。但是,我们可以通过自定义过滤器来修改和扩展此行为。在`@ComponentScan`中添加属性includeFilters或excludeFilters(或在XML的中配置或)。每个过滤器元素都需要type和expression属性。
下表描述了过滤选项:
通过@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,源码和官网必不可少。