JavaBean和SpringBean的區別及創建SpringBean方式

一:對象,JavaBean,SpringBean的區別

1.什麼是JavaBean

javaBean要求所有屬性為私有,該類必須有一個公共無參構造函數,private屬性必須提供公共的Getter setter給外部訪問

/**
 * @author yzh
 * @date 2021/4/29 8:42
 **/
public class User {
    //javaBean要求所有屬性為私有,該類必須有一個公共無參構造函數,private屬性必須提供公共的Getter setter給外部訪問
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

2.什麼是SpringBean

SpringBean是受Spring管理的對象,所有能受Spring管理的對象都可以是SpringBean

3.SpringBean和JAVABean的區別

  • 用處不同:傳統javabean更多地作為值傳遞參數,而spring中的bean用處幾乎無處不在,任何組件都可以被稱為bean
  • 寫法不同:傳統javabean作為值對象,要求每個屬性都提供getter和setter方法;但spring中的bean隻需為接受設值註入的屬性提供setter方法

生命周期不同:傳統javabean作為值對象傳遞,不接受任何容器管理其生命周期;spring中的bean有spring管理其生命周期行為

二:如何定義一個SpringBean

準備工作:引入Spring依賴包

<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.14.RELEASE</version>
</dependency>

1.通過ClassPathXmlApplicationContext

通過ClassPathXmlApplicationContext需要指定configLocation,所有我們現在resources目錄下新建一個Spring.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
    <!-- 使用設值註入方式裝配實例 -->
    <bean id="user1" class="org.example.bean.User">
        <property name="name" value="zhangsan" />
    </bean>
    <!-- 使用構造方法裝配實例 -->
    <!--使用構造方法裝配需要在相應類提供構造函數-->
    <bean id="user2" class="org.example.bean.User">
        <constructor-arg index="0" value="lisi" />
    </bean>
</beans>

同時相應對象重寫toString方法,便於更好觀察user1和user2

package org.example.bean;
/**
 * @author yzh
 * @date 2021/4/29 8:42
 **/
public class User {
    //javaBean要求所有屬性為私有,該類必須有一個公共無參構造函數,private屬性必須提供公共的Getter setter給外部訪問
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public User(String name) {
        this.name = name;
    }
    public User() {
    }
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                '}';
    }
}

運行測試類

package org.example.bean;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 * @author yzh
 * @date 2021/4/29 8:45
 **/
public class Main {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext();
        classPathXmlApplicationContext.setConfigLocation("Spring.xml");
        classPathXmlApplicationContext.refresh();
        User user1 = classPathXmlApplicationContext.getBean("user1",User.class);
        System.out.println(user1);
        User user2 = classPathXmlApplicationContext.getBean("user2", User.class);
        System.out.println(user2);
    }
}

運行結果如下

User{name=’zhangsan’}

User{name=’lisi’}

2.通過AnnotationConfigApplicationContext底層

也是通過BeanDefinition實現

*@Bean@Component@Service@Controller都可以;一般@Service用於Service層,@Controller用於Controller層,此處以@Bean為例

新建一個Config類,並給User打上@Bean標簽

package org.example.bean;
import org.springframework.context.annotation.Bean;
/**
 * @author yzh
 * @date 2021/4/29 9:20
 **/
public class Config {
    @Bean
    public User user(){
        return  new User();
    }
}

通過AnnotationConfigApplicationContext獲取bean,並打印bean對象

package org.example.bean;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 * @author yzh
 * @date 2021/4/29 8:45
 **/
public class Main {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
        annotationConfigApplicationContext.register(Config.class);
        annotationConfigApplicationContext.refresh();
        User user = annotationConfigApplicationContext.getBean("user",User.class);
        System.out.println(user);
    }
}

運行結果

User{name=’null’}

3.通過BeanDefinition

package org.example.bean;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 * @author yzh
 * @date 2021/4/29 8:45
 **/
public class Main {
    public static void main(String[] args) {
  
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
 
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        //定義一個Bean
        beanDefinition.setBeanClass(User.class);
        //把生成的Bean註冊到容器中
        annotationConfigApplicationContext.refresh();
        annotationConfigApplicationContext.registerBeanDefinition("userTest",beanDefinition);
        User userTest = annotationConfigApplicationContext.getBean("userTest", User.class);
        System.out.println(userTest);
    }
}

運行結果

User{name=’null’}

4.通過FactoryBean

4.1通過FactoryBean與註解方式

首先新建一個Person類

package org.example.bean;
import org.springframework.stereotype.Component;
/**
 * @author yzh
 * @date 2021/4/29 10:00
 **/
public class Person {
}

然後新建一個PersonFactoryBean類,並實現FactoryBean接口,重寫其方法,為其打上@component註解, 此處和在Person類上打註解是同一效果

package org.example.bean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.stereotype.Component;
/**
 * @author yzh
 * @date 2021/4/29 10:01
 **/
@Component("person")
public class PersonFactoryBean implements FactoryBean {
    @Override
    public Object getObject() throws Exception {
        return new Person();
    }
    @Override
    public Class<?> getObjectType() {
        return Person.class;
    }
}

其次添加一個Config類打上@ComponentScan(“org.example.bean”),目的是為瞭掃描包下的註解

package org.example.bean;
import org.springframework.context.annotation.ComponentScan;
/**
 * @author yzh
 * @date 2021/4/29 9:20
 **/
@ComponentScan("org.example.bean")
public class Config {
}

最後通過AnnotationConfigApplicationContext獲取Bean

package org.example.bean;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 * @author yzh
 * @date 2021/4/29 8:45
 **/
public class Main {
    public static void main(String[] args) {
         //Config類為包掃描配置類
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(Config.class);
        Person person = annotationConfigApplicationContext.getBean("person", Person.class);
        System.out.println(person);
    }
}

運行結果

org.example.bean.Person@28ac3dc3

4.2通過Factory和BeanDefinition

1.同4.1一樣新建一個Person類

2.同4.1一樣新建一個PersonFactoryBean類,實現FactoryBean接口,但是不打註解

3.通過BeanDefinition獲取對象

此處和註解生成的差別在於通過BeanDefinition註冊的會生成兩個Bean對象,一個是person對應的類型是Person,另一個是&person對應的類型是PersonFactoryBean,通過下面代碼的getBean方法可以看出來!!

package org.example.bean;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 * @author yzh
 * @date 2021/4/29 8:45
 **/
public class Main {
    public static void main(String[] args) {
  
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(Config.class);
    
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        ////定義一個Bean
        beanDefinition.setBeanClass(PersonFactoryBean.class);
        //把生成的Bean註冊到容器中
        //annotationConfigApplicationContext.refresh();
        //此處會生成2個Bean對象 第一個對象為&person對應的類型的PersonFactoryBean 第二個對象為person對應的類型為Person;
        annotationConfigApplicationContext.registerBeanDefinition("person",beanDefinition);
        PersonFactoryBean personFactoryBean = annotationConfigApplicationContext.getBean("&person", PersonFactoryBean.class);
        System.out.println(personFactoryBean);
        Person person = annotationConfigApplicationContext.getBean("person", Person.class);
        System.out.println(person);
    }
}

運行結果如下

org.example.bean.PersonFactoryBean@3aeaafa6

org.example.bean.Person@76a3e297

FactoryBean接口提供三個方法,但是我們重寫瞭兩個方法,這是因為另外一個方法是默認實現瞭的

FactoryBean接口方法如下:

package org.springframework.beans.factory;
import org.springframework.lang.Nullable;
public interface FactoryBean<T> {
    
    String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
    @Nullable
    T getObject() throws Exception;
    
    @Nullable
    Class<?> getObjectType();
    //默認實現方法,是否是單例
    default boolean isSingleton() {
        return true;
    }
}

5.通過Supplier

package org.example.bean;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.function.Supplier;
/**
 * @author yzh
 * @date 2021/4/29 8:45
 **/
public class Main {
    public static void main(String[] args) {
     
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
        annotationConfigApplicationContext.refresh();
        annotationConfigApplicationContext.registerBean(User.class, new Supplier<User>() {
            @Override
            public User get() {
                User user = new User();
                user.setName("123");
                return user;
            }
        });
        User user = annotationConfigApplicationContext.getBean("user", User.class);
        System.out.println(user);
    }
}

bean的註入方式本文隻是提供瞭多種api,很多情況下底層其實用的都是一樣的東西,隻是提供瞭不同的使用方式,具體可以通過源碼查看。

以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。

推薦閱讀: