SpringBoot 学习笔记一 Spring快速入门

bean的装配

新建一个maven工程,引入依赖

    <dependencies>
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-contextartifactId>
        dependency>
    dependencies>

引入spring-context之后发现spring-core、spring-bean、spring-aop、spring-context、spring-expression、都引入进来了,这是因为spring-context内部依赖了其他几个包所以一同引了过来。
SpringBoot 学习笔记一 Spring快速入门_第1张图片
项目结构目录如图所示,创建三个空的bean,无需属性和方法。
MyConfig类


/**
 * @Configuration 注解标志该类为配置类,配置bean有三种方式
 */
@Configuration
public class MyConfig {
    /**
     * 直接装配
     */
    @Bean(name = "myBean")//名字默认为方法名
    public MyBean createMyBean(){
        return new MyBean();
    }

    /**
     * 通过FactoryBean来装配
     * 你会发现我们new的是一个JeepFactoryBean但是返回的却是Jeep
     */
    @Bean(name = "jeep")
    @Scope(value = "prototype")//scope默认为单例,改为prototype为多例
    public JeepFactoryBean createJeepFactoryBean(){
        return new JeepFactoryBean();
    }

    /**
     * 通过factory 装配
     * 注入一个CarFactory,Spring容器会自动从容器中找相应类型的bean注入进去
     */
    @Bean
    public CarFactory createCarFactory(){
        return new CarFactory();
    }
    @Bean(name = "car")
    public Car createCar(CarFactory carFactory){
        return carFactory.createCar();
    }
}

JeepFactoryBean需实现FactoryBean并实现他的三个方法

package com.yjj.factory;

import com.yjj.bean.Jeep;
import org.springframework.beans.factory.FactoryBean;

public class JeepFactoryBean implements FactoryBean{

    @Override
    public Jeep getObject() throws Exception {
        return new Jeep();
    }

    @Override
    public Class getObjectType() {
        return Jeep.class;
    }

    @Override
    public boolean isSingleton() {
        return true;//true为单例模式,false不是单利模式
    }
}

CarFactory

public class CarFactory {
    public Car createCar(){
        return new Car();
    }
}

测试类

public class App {
    public static void main(String[] args){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
        System.out.println(context.getBean(MyBean.class));
        System.out.println(context.getBean("myBean"));
        System.out.println(context.getBean(Jeep.class));
        System.out.println(context.getBean("jeep"));
        System.out.println(context.getBean("&jeep"));//获取factoryBean本身
        System.out.println(context.getBean(JeepFactoryBean.class));//获取factoryBean本身
       System.out.println(context.getBean(Car.class));
       System.out.println(context.getBean("car"));

    }
}

以下是输出

com.yjj.bean.MyBean@5d20e46
com.yjj.bean.MyBean@5d20e46
com.yjj.bean.Jeep@709ba3fb
com.yjj.bean.Jeep@709ba3fb
com.yjj.factory.JeepFactoryBean@3d36e4cd
com.yjj.factory.JeepFactoryBean@3d36e4cd
com.yjj.bean.Car@6a472554
com.yjj.bean.Car@6a472554

指定bean初始化和销毁方法

有时候在初始化和销毁bean时我们想做一些刺激的事情,可以通过以下三种方式

1.实现接口方法


public class Cat implements InitializingBean,DisposableBean {
    /**
     * bean初始化时候
     * @throws Exception
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("-----init1-----");
    }

    /**
     * bean销毁时
     * @throws Exception
     */
    @Override
    public void destroy() throws Exception {
        System.out.println("-----destroy1-----");
    }
}

2.配置bean时指定方法名

    @Bean(initMethod = "init",destroyMethod = "destroy")
    public Dog createDog(){
        return new Dog();
    }

3.通过注解方式

public class Bird{
    @PostConstruct
    public void init(){
        System.out.println("----init3----");
    }
    @PreDestroy
    public void destroy(){
        System.out.println("----destory3-----");
    }
}

在获取bean时效果如下

-----init1-----
----init2----
----init3----
com.yjj.bean.MyBean@448ff1a8
com.yjj.bean.MyBean@448ff1a8
com.yjj.bean.Jeep@7f77e91b
com.yjj.bean.Jeep@6328d34a
com.yjj.factory.JeepFactoryBean@145eaa29
com.yjj.factory.JeepFactoryBean@15bb6bea
com.yjj.bean.Car@8b96fde
com.yjj.bean.Car@8b96fde
com.yjj.bean.Cat@2d2e5f00
com.yjj.bean.Dog@1e67a849
com.yjj.bean.Bird@57d5872c
--show--
com.yjj.service.UserService@667a738
----destory3-----
----destory2-----
-----destroy1-----

通过注解方式注入bean

这是我们通常使用的一种方式,在bean类上方加上@Component、@Controller、@Service、@Repository注解,该类就会被自动注入Spring容器,当我们需要在别的类注入该bean时,只需要在属性上加上@Autowired注解即可,甚至不需要写get、set方法,我们通过@AutoWired注解注入bean时,自动通过类型装配,如果Spring容器中该类型的bean有两个,会选取name=属性名首字母小写的bean注入。
但是当你手动通过context获取bean时,需要显式指定获取哪一个bean否则Spring会不知道到底注入哪个bean而报错,如下我们在UserService上加入@Service注解,此时会在Spring容器注入一个name为userService的bean,我们再在MyConfig类再创建一个bean

    @Bean
    @Primary//此注解为当有多个UserService类型的bean时,此为注入对象
    public UserService createUserService(){
        return new UserService();
    }

如果不加primary会报错

Exception in thread "main" org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.yjj.service.UserService' available: expected single matching bean but found 2: userService,createUserService

解决方法
除了上述的@Primary注解,还可以在使用bean时加上@Qualifier注解指定使用哪一个bean,当出现同名的bean时,那其实就是一个bean,emm。。就是你用了@Component注解,又同时手动去装配了一个bean,name指定成bean类的首字母小写,name其实这两个是同一个bean。
也可以使用@Resource注解注入bean,同时@Inject注解也可以注入bean但是@Inject注解不是jdk自带的,需要引入jar包。

知识点

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class,User.class, UserService.class, UserDao.class);

该类除了此构造方法还提供了一个扫描包的构造方法,在构造函数里传入一个包名,Spring会去自动扫描该包下带@Component、@Service、@Controller、@Repository的注解类,或者是在配置类中配置的bean并注入Spring容器。
还可以通过@ComponentScan注解添加扫描包basePackage=“包名”,还可以添加排除扫描类excludeFilters,排除有五种方式你可以去研究一下。

如何让一个bean被spring管理起来

  • 写一个配置类@Configuration注解,加@Bean注解
  • 直接在Bean上加@Component等注解

如何在一个类中依赖别的bean

  • @Autowired或@Resource
  • 实现ApplicationContextAwre接口,写一个set方法
  • 在构造函数中传入该bean,spring容器会自动在容器中找到相应的bean注入(有缺陷,不推荐使用)有多个构造函数的话不能用。

BeanPostProcessor

实现这个接口的两个方法可以在每个bean实例化之前和之后做一些处理,spring容器每实例化一个bean,都会执行一次该方法

动态向spring容器注入bean

实现BeanDefinitionRegistryPostProcessor
在postProcessBeanDefinitionRegistry方法

BeanDefinitionBuilder bdb=BeanDEfinitionBuilder.rootBeanDfinition(BeanName.class);
bdb.addPropertyValue("name","yinjunjie");
registry.registerBeanDefinition("person",bdb.getBeanDefinition());

你可能感兴趣的:(SpringBoot)