spring笔记②——springIOC

spring bean生命周期回调

官网描述
https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-factory-lifecycle
一共三种方式
在这里插入图片描述

  1. 在回调方法上加@PostConstruct@PreDestroy注解
  2. 实现InitializingBeanDisposableBean接口中的回调方法
  3. 在xml配置文件中配置bean的时候加上init-methoddestroy-method属性

方法一(注解)

在初始化的回调方法上加@PostConstruct注解,在bean销毁时的回调方法上加@PreDestroy注解

@PostConstruct
public void init(){
    System.out.println("DemoServiceImpl初始化");
}
@PreDestroy
public void destroy(){
    System.out.println("DemoServiceImpl被销毁了");
}

方法二(接口)

bean初始化的回调,实现下面的接口
在这里插入图片描述
bean销毁的回调,实现下面的接口
在这里插入图片描述
这种方法需要注入spring的接口,侵入性太强,不建议使用

public class DemoServiceImpl implements DemoService, InitializingBean, DisposableBean {
    @Override
    public void destroy() throws Exception {
    }
    @Override
    public void afterPropertiesSet() throws Exception {
    }

方法三(xml)

在配置文件中的bean中定义init-method属性,方法名可以自定义,初始化回调

<bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>
public class ExampleBean {

    public void init() {
        // do some initialization work
    }
}

销毁回调

<bean id="exampleInitBean" class="examples.ExampleBean" destroy-method="cleanup"/>
public class ExampleBean {
    public void cleanup() {
        // do some destruction work (like releasing pooled connections)
    }
}

单例中的多例问题

如果在单例的类中注入了一个多例的类,那么多例的类并不会因为第二次得到单例的类而产生新的对象

这样就在单例的类中注入了一个多例的类

@Repository
@Scope("prototype")
public class DemoDaoImpl1 implements DemoDao{
    @Override
    public void test() {
        System.out.println("zzz1");
    }
}
@Service
public class DemoServiceImpl implements DemoService {

    @Autowired
    private DemoDao demoDaoImpl1;

    @Override
    public void test() {
        demoDaoImpl1.test();
        System.out.println("dao"+demoDaoImpl1.hashCode());
        System.out.println("service"+this.hashCode());
    }
}

获得三次

public static void main(String[] args) {
    AnnotationConfigApplicationContext annotationConfigApplicationContext =
            new AnnotationConfigApplicationContext(Springcfg.class);
    DemoService demoService= (DemoService) annotationConfigApplicationContext.getBean("demoServiceImpl");
    demoService.test();

    DemoService demoService1= (DemoService) annotationConfigApplicationContext.getBean("demoServiceImpl");
    demoService1.test();

    DemoService demoService2= (DemoService) annotationConfigApplicationContext.getBean("demoServiceImpl");
    demoService2.test();
}

下面是结果

zzz1
dao1800659519
service1691538257
zzz1
dao1800659519
service1691538257
zzz1
dao1800659519
service1691538257

可以看出,DemoDao依然是同一个对象,并没有体现出多例表现

那么如果想要每一次都能获得不一样的对象,必须对DemoServiceImpl做一些处理

可以改变注入的方式,这样每次拿都是重新去创建一个对象,@Lookup注解也是先根据返回值的类型注入的,所以如果只有一个实现类就可以无需关心括号内的值,但是如果有两个实现类,那么就会根据括号内的值找到相同类名的实现类注入

@Service
public abstract class DemoServiceImpl implements DemoService {

    @Lookup("demoDaoImpl")
    protected abstract DemoDao createDemoDao();

    @Override
    public void test() {
        System.out.println("dao"+createDemoDao().hashCode());
        System.out.println("service"+this.hashCode());
    }
}

@Autowired和@Resource的区别

  • @Autowired默认是根据类型注入的,但如果有相同的实现类,那么会根据属性名来注入
  • @Resource默认是根据属性名注入的

依赖注入时的重复依赖问题

如果依赖注入时注入的依赖同时有两个实现类,这种情况下就会出现问题
在这里插入图片描述

@Autowired
private DemoDao demoDao;

解决办法如下

@Primary

在需要注入的实现上加注解@Primary

@Primary
public class DemoDaoImpl implements DemoDao{

@Qualifier

在注入时加注解@Qualifier(“需要注入的实现类名”)

@Autowired
@Qualifier("demoDaoImpl")
private DemoDao demoDao;

@Profile

@Profile可以加在类的上面,设置一个名字,这样在初始化容器时注册其中一个,这样另外的实现就不会生成bean

@Profile("demoDaoImpl")
public class DemoDaoImpl implements DemoDao{

在配置时要激活要注入的类,其他的实现类会直接忽略不会生成bean

public static void main(String[] args) {
    AnnotationConfigApplicationContext annotationConfigApplicationContext =
            new AnnotationConfigApplicationContext();
    //激活要注入的类
    annotationConfigApplicationContext.getEnvironment().setActiveProfiles("demoDaoImpl");
    //注册spring配置类
    annotationConfigApplicationContext.register(Springcfg.class);
    //重新刷新配置,这样才能实现配置
    annotationConfigApplicationContext.refresh();
    DemoService demoService= (DemoService) annotationConfigApplicationContext.getBean("demoServiceImpl");
    demoService.test();
}

加快bean初始化的速度

在这里插入图片描述

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-indexer</artifactId>
    <version>5.1.9.RELEASE</version>
    <optional>true</optional>
</dependency>

如果加上这个依赖就可以更快地生成bean(适合需要加载很多bean的场景),原理是在编译时会生成bean目录的索引,这样spring在扫描的时候就可以更快找到生成bean的类

@Bean

用注解和javaConfig的方式配置bean

如果在配置bean的时候要注入属性,那么需要在方法上加@AutoWired注解,但是spring5之后可以不加

在javaConfig类中配置了mybatis的相关参数

@Configuration
@ComponentScan("com.zdd")
public class Springcfg {

    @Bean
    @Autowired
    public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){
        SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
        sqlSessionFactory.setDataSource(dataSource);
        return sqlSessionFactory;
    }
    @Bean
    public DataSource dataSource(){
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setUrl("jdbc:mysql://localhost:3306//mysql01");
        dataSource.setDriverClassName("com.mysql.jdbc.Dirver");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
        return dataSource;
    }
}

bean中的循环引用

分几种情况

  • 两者都是单例的
    因为有缓冲区
    先把baen创建出来放在缓存中,需要引用的时候拿出来

  • 两者都是多例
    因为没有缓存,每一个都是原型,所以会在引用时反复创建,这样就会造成溢出泄露问题,时不允许的

  • 一个单例和一个多例同两者都是单例
    原因在上面中的单例中引用了多例的情况

depends-on

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值