spring基础

依赖查找:


BeanFactory beanFactory = new ClassPathXmlApplicationContext("basic_di/inject-set.xml");

Person person = beanFactory.getBean(Person.class);

根据type查找一组对象:

ApplicationContext ctx = new ClassPathXmlApplicationContext("basic_dl/quickstart-oftype.xml");
Map<String, DemoDao> beans = ctx.getBeansOfType(DemoDao.class);
beans.forEach((beanName, bean) -> {
    System.out.println(beanName + " : " + bean.toString());
});

根据注解查找:
ApplicationContext 中有一个方法叫 getBeansWithAnnotation ,它可以传入一个注解的 class ,返回所有被这个注解标注的 bean 。

ApplicationContext ctx = new ClassPathXmlApplicationContext("basic_dl/quickstart-withanno.xml");
Map<String, Object> beans = ctx.getBeansWithAnnotation(Color.class);
beans.forEach((beanName, bean) -> {
    System.out.println(beanName + " : " + bean.toString());
});

获取IOC容器中的所有Bean:ApplicationContext的getBeanDefinitionNames()方法

ApplicationContext ctx = new ClassPathXmlApplicationContext("basic_dl/quickstart-withanno.xml");
String[] beanNames = ctx.getBeanDefinitionNames();
// 利用jdk8的Stream快速编写打印方法
Stream.of(beanNames).forEach(System.out::println);

查找是否有某个bean:ApplicationContext.containsBean()
延迟查找:ApplicationContext.getBeanProvider()

ObjectProvider<Dog> dogProvider = ctx.getBeanProvider(Dog.class);
Dog dog = dogProvider.getIfAvailable();
if (dog == null) {
    dog = new Dog();
}
//或者
 Dog dog = dogProvider.getIfAvailable(() -> new Dog());

依赖注入: property注入, value直接赋值,ref引用

<bean id="person" class="com.linkedbear.spring.basic_di.a_quickstart_set.bean.Person">
    <property name="name" value="test-person-byset"/>
    <property name="age" value="18"/>
</bean>
<bean id="cat" class="com.linkedbear.spring.basic_di.a_quickstart_set.bean.Cat">
    <property name="name" value="test-cat"/>
    <!-- ref引用上面的person对象 -->
    <property name="master" ref="person"/>
</bean>

setter属性注入:

//  xml:
<bean id="person" class="com.linkedbear.spring.basic_di.a_quickstart_set.bean.Person">
    <property name="name" value="test-person-byset"/>
    <property name="age" value="18"/>
</bean>
//  注解:
@Bean
public Person person() {
    Person person = new Person();
    person.setName("test-person-anno-byset");
    person.setAge(18);
    return person;
}

构造器注入:

//xml
<bean id="person" class="com.linkedbear.spring.basic_di.b_constructor.bean.Person">
    <constructor-arg index="0" value="test-person-byconstructor"/>
    <constructor-arg index="1" value="18"/>
</bean>
//注解
@Bean
public Person person() {
    return new Person("test-person-anno-byconstructor", 18);
}

@Component下的属性注入:

@Value("black-value-anno")
private String name;

//外部引入:从.properties文件中引入
@Configuration
@ComponentScan("com.linkedbear.spring.basic_di.c_value_spel.bean")
@PropertySource("classpath:basic_di/value/red.properties")
public class InjectValueConfiguration {
}

@Value("${red.name}")
private String name;

//xml中
<bean class="com.linkedbear.spring.basic_di.c_value_spel.bean.Red">
    <property name="name" value="${red.name}"/>
    <property name="order" value="${red.order}"/>
</bean>

自动注入:@Autowired

//1
@Autowired
private Person person;
//2
@Autowired
public Dog(Person person) {
    this.person = person;
}
//3
@Autowired
public void setPerson(Person person) {
    this.person = person;
}
//4
@Bean
@Autowired // 高版本可不标注
public Cat cat(Person person) {
    Cat cat = new Cat();
    cat.setName("mimi");
    cat.setPerson(person);
    return cat;
}

存在多个同类型的bean时,使用@Autowired会报错:
1.使用@Qualifier显示指定bean的id
2.@Primary标记优先的bean
3.修改变量名,与bean的id对应

//1
@Autowired
@Qualifier("administrator")
private Person person;
//2
@Bean
@Primary
public Person master() {
    Person master = new Person();
    master.setName("master");
    return master;
}
//3
@Autowired
private Person administrator;

@Autowired注入的原理逻辑:
先拿属性对应的类型,去 IOC 容器中找 Bean ,如果找到了一个,直接返回;如果找到多个类型一样的 Bean , 把属性名拿过去,跟这些 Bean 的 id 逐个对比,如果有一个相同的,直接返回;如果没有任何相同的 id 与要注入的属性名相同,则会抛出 NoUniqueBeanDefinitionException 异常。
注入一组对象:

@Autowired
private List<Person> persons;

@Resource注解:按属性名注入 (先按名字注入,没写就是属性名,找不到name再按type注入)

@Resource(name = "master")
private Person person;


注解驱动:AnnotationConfigApplicationContext

@Bean(name = "aaa") // 4.3.3之后可以直接写value,name就是id,不写的话是方法名作为id
public Person person() {
    return new Person();
}
@Component("aaa")  //模式注解,不指定的话id就是类名小写
public class Person { }
ApplicationContext ctx = new AnnotationConfigApplicationContext(QuickstartConfiguration.class); //可以传入配置类,也可以传入根包
Person person = ctx.getBean(Person.class);
System.out.println(person);

@ComponentScan:搭配@Configuration一起用,扫描指定路径包及子包下的所有 @Component 组件;如果不指定扫描路径,则默认扫描本类所在包及子包下的所有 @Component 组件。
AnnotationConfigApplicationContext 的构造方法中有一个类型为 String 可变参数的构造方法:可以扫描对应包下的@component组件

ApplicationContext ctx = new AnnotationConfigApplicationContext("com.linkedbear.spring.annotation.c_scan.bean");

xml中启用组件扫描:

<context:component-scan base-package="com.linkedbear.spring.annotation.c_scan.bean"/>

@Configuration也是@Component
xml中引入注解:在 xml 中要引入注解配置,需要开启注解配置,同时注册对应的配置类

<context:annotation-config />
<bean class="com.linkedbear.spring.annotation.d_importxml.config.AnnotationConfigConfiguration"/>

注解引入xml:在注解配置中引入 xml ,需要在配置类上标注 @ImportResource 注解,并声明配置文件的路径:

@Configuration
@ImportResource("classpath:annotation/beans.xml")
public class ImportXmlAnnotationConfiguration {
    
}

bean的类型与作用域:
类型分为普通bean和工厂bean,作用域分为单例,原型,request,session,application,websocket
factorybean:

public interface FactoryBean<T> {
    // 返回创建的对象
    @Nullable
    T getObject() throws Exception;

    // 返回创建的对象的类型(即泛型类型)
    @Nullable
    Class<?> getObjectType();

    // 创建的对象是单实例Bean还是原型Bean,默认单实例
    default boolean isSingleton() {
        return true;
    }
}

public class ToyFactoryBean implements FactoryBean<Toy> {
    
    private Child child;
    
    @Override
    public Toy getObject() throws Exception {
        switch (child.getWantToy()) {
            case "ball":
                return new Ball("ball");
            case "car":
                return new Car("car");
            default:
                // SpringFramework2.0开始允许返回null
                // 之前的1.x版本是不允许的
                return null;
        }
    }
    
    @Override
    public Class<Toy> getObjectType() {
        return Toy.class;
    }
    
    public void setChild(Child child) {
        this.child = child;
    }
}

    @Bean
    public Child child() {
        return new Child();
    }
    
    @Bean
    public ToyFactoryBean toyFactory() {
        ToyFactoryBean toyFactory = new ToyFactoryBean();
        toyFactory.setChild(child());
        return toyFactory;
    }

factoryBean的创建时机:FactoryBean是在IOC初始化时创建的,FactoryBean 生产 Bean 的机制是延迟生产。
作用域与创建时机:@Scope(),singlieton的创建时机为IOC容器创建时,property的创建时机为getbean时
request:请求Bean,每次客户端向 Web 应用服务器发起一次请求,Web 服务器接收到请求后,由 SpringFramework 生成一个 Bean ,直到请求结束
session :会话Bean,每个客户端在与 Web 应用服务器发起会话后,SpringFramework 会为之生成一个 Bean ,直到会话过期
application :应用Bean,每个 Web 应用在启动时,SpringFramework 会生成一个 Bean ,直到应用停止(有的也叫 global-session )
websocket :WebSocket Bean ,每个客户端在与 Web 应用服务器建立 WebSocket 长连接时,SpringFramework 会为之生成一个 Bean ,直到断开连接

静态工厂创建bean:静态工厂本身不会被注册到 IOC 容器中

public class CarStaticFactory {
    
    public static Car getCar() {
        return new Car();
    }
}

<bean id="car2" class="com.linkedbear.spring.bean.c_instantiate.bean.CarStaticFactory" factory-method="getCar"/>

//编程式
@Bean
public Car car2() {
    return CarStaticFactory.getCar();
}

实例工厂创建bean:

public class CarInstanceFactory {
    public Car getCar() {
        return new Car();
    }
}

<bean id="carInstanceFactory" class="com.linkedbear.spring.bean.c_instantiate.bean.CarInstanceFactory"/>  //先创建示例工厂
<bean id="car3" factory-bean="carInstanceFactory" factory-method="getCar"/> //再用实例工厂创建bean

//编程式
@Bean
public Car car3(CarInstanceFactory carInstanceFactory) {
    return carInstanceFactory.getCar();
}

bean的生命周期:
实例化-初始化-运行-销毁-垃圾回收
可干预阶段:初始化与销毁
init-method&destroy-method:在 IOC 容器初始化之前,默认情况下 Bean 已经创建好了,而且完成了初始化动作;容器调用销毁动作时,先销毁所有 Bean ,最后 IOC 容器全部销毁完成。bean的生命周期中,先对属性赋值,再执行init-method 标记的方法。原型bean的生命周期与IOC容器无关

public class Cat {
    
    private String name;
    
    public void setName(String name) {
        this.name = name;
    }
    
    public void init() {
        System.out.println(name + "被初始化了。。。");
    }
    public void destroy() {
        System.out.println(name + "被销毁了。。。");
    }
}
//xml
<bean class="com.linkedbear.spring.lifecycle.a_initmethod.bean.Cat"
      init-method="init" destroy-method="destroy">
    <property name="name" value="mimi"/>
//编程式
@Bean(initMethod = "init", destroyMethod = "destroy")
public Dog dog() {
    Dog dog = new Dog();
    dog.setName("wangwang");
    return dog;
}

对于@Compoment创建的bean,使用@PostConstruct 、@PreDestroy 来对应 init-method 和 destroy-method 。

@Component
public class Pen {
    
    private Integer ink;
    
    @PostConstruct
    public void addInk() {
        System.out.println("钢笔中已加满墨水。。。");
        this.ink = 100;
    }
    
    @PreDestroy
    public void outwellInk() {
        System.out.println("钢笔中的墨水都放干净了。。。");
        this.ink = 0;
    }
    
    @Override
    public String toString() {
        return "Pen{" + "ink=" + ink + '}';
    }
}
posted @ 2022-10-03 21:58  无极是一种信仰  阅读(50)  评论(0编辑  收藏  举报