在 Spring中 建立 JavaBean

在 Spring中 建立 JavaBean

Spring 框架的最核心功能之一是 DI (Dependency Injection), 也就是依賴注入。java

DI 的底層原理是反射技術,對 JavaBean 的屬性進行賦值,從而達到 A 到 B 模塊的解耦。Spring 提供 DI 容器,對須要關聯的 JavaBean、不須要關聯的 JavaBean 的建立、銷燬都要進行統一的調度和管理。git

在咱們的程序中,咱們將不使用 new 關鍵字的建立對象,而是交給 DI 容器管理生命週期,以及多個 JavaBean 之間的注入關係。從技術上說,就是使用反射將接口和實現相分離。github

但在此以前,咱們來看看如何使用 Spring 框架,以及幾種建立 JavaBean 的方式。spring

1. 不使用 Spring 框架的傳統方式

先建立一個 Java Project,建立一個保存操做的類 Save數組

package save;

public class Save {
    public void save() {
        System.out.println("save 方法!");
    }
}

一個測試類 Testapp

package test;

import save.Save;

public class Test {
    private Save save = new Save();
 
    public Save getSave() {
           return save;
    }

    public void setSave(Save save) {
            this.save = save;
    }

    public static void main(String[] args) {
           Test test = new Test();
            test.getSave().save();
    }
}

運行結果:框架

運行結果一

2. 使用 xml 聲明法建立對象

在 src 中建立 applicationContext.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"
      xsi:schemaLocation="http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="userinfo1" class="entity.Userinfo"></bean>
</beans>

<bean> 標籤告訴 Spring 要建立 entity 包下的 Userinfo 類的對象,放在 DI 容器裏,在容器裏的 id 是 userinfo1。Userinfo 以下:測試

package entity;

public class Userinfo {
	public Userinfo() {
		System.out.println("類 Userinfo 被實例化 = " + this);
	}
}

測試類 Test:this

package test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test1 {
	public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
	}
}

運行結果:

2

若是 applicationContext.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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="userinfo1" class="entity.Userinfo"></bean>
    <bean id="userinfo2" class="entity.Userinfo"></bean>
</beans>

若是經過 getBean(Userinfo.class) 方法獲取對象的話就會拋出 NoUniqueBeanDefinitionException 異常,由於 Spring 找到了多個對象,不知道返回哪個。

package test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import entity.Userinfo;

public class TestNoUnique {
	public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
		Userinfo userinfo = context.getBean(Userinfo.class);
	}
}

拋出如下異常 :

3

如何解決呢? 不要使用 getBean(Userinfo.class); , 使用 getBean(String id); 這樣就能夠得到 id 對應的惟一對象,而解決異常。

package test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import entity.Userinfo;

public class Test1_1 {
	public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
		Userinfo userinfo1 = (Userinfo)context.getBean("userinfo1");
		Userinfo userinfo2 = (Userinfo)context.getBean("userinfo2");
		System.out.println(userinfo1);
		System.out.println(userinfo2);
	}
}

運行結果, 能夠看到經過 id 獲取的對象和 Spring 建立的對象是同一個對象:

4

總結: getBean(Userinfo.class) 適用於只有一個 Userinfo 類實例對象的狀況,而有多個 Userinfo 類對象的時候就須要使用 getBean(String id) 方法。

3. 使用 xml 和 Annotation 註解混合的方式來建立對象

使用 <context:component-scan base-package=""> 建立對象

<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
	<context:component-scan base-package="entity"></context:component-scan>
</beans>

使用 @Component 註解,這樣 Userinfo 能被 <context:component-scan base-package="entity"> 識別並建立實例化對象。

package entity;

import org.springframework.stereotype.Component;

@Component
public class Userinfo {
	public Userinfo() {
		System.out.println("Userinfo 構造方法執行了:" + this);
	}
}

測試類 Test 類,運行結果:

package test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {
	public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
	}
}

5

getBean(Userinfo.class) 的方式運行:

package test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import entity.Userinfo;

public class Test2 {
	public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
		Userinfo userinfo = (Userinfo)context.getBean(Userinfo.class);
		System.out.println("main run " + userinfo);
	}
}

6

咱們也能夠看到經過 id 獲取的對象和 Spring 建立的對象是同一個對象。

4. 使用全註解建立出對象

全註解配置法也稱 JavaConfig 配置法。註解 @Configuration 起着和 <beans> 標籤同樣的全局配置做用,這樣咱們就不須要 xml 配置方式就能建立 JavaBean 了。而註解 @Bean 就和 <bean> 標籤的功能是同樣的,用來聲明 JavaBean。

@Bean 註解聲明建立對象的方法是名稱能夠是任意的,但必須有返回值。

package tools;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import entity.Userinfo;

@Configuration
public class CreateBean {
	@Bean
	public Userinfo getUserinfo() {
		Userinfo userinfo1 = new Userinfo();
		System.out.println("建立 userinfo1 = " + userinfo1);
		return userinfo1;
	}
	
	@Bean
	public Userinfo createUserinfo() {
		Userinfo userinfo2 = new Userinfo();
		System.out.println("建立 userinfo2 = " + userinfo2);
		return userinfo2;
	}
}
package entity;

import org.springframework.stereotype.Component;

public class Userinfo {
	public Userinfo() {
		System.out.println("Userinfo 構造方法執行了:" + this);
	}
}
package test;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Test4 {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext context = 
				new AnnotationConfigApplicationContext("tools");
	}
}

運行結果:

7

使用全註解發生 NoUniqueBeanDefinitionException 異常,以及解決方法

將 Test4 類的代碼加上一行代碼

package test;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import entity.Userinfo;

public class Test4 {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext context = 
				new AnnotationConfigApplicationContext("tools");
                Userinfo userinfo = context.getBean(Userinfo.class);
	}
}

8

解決辦法是給 @Bean 添加一個 name

package tools;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import entity.Userinfo;

@Configuration
public class CreateBean {
	@Bean(name = "userinfo1")
	public Userinfo getUserinfo() {
		Userinfo userinfo1 = new Userinfo();
		System.out.println("建立 userinfo1 = " + userinfo1);
		return userinfo1;
	}
	
	@Bean(name = "userinfo2")
	public Userinfo createUserinfo() {
		Userinfo userinfo2 = new Userinfo();
		System.out.println("建立 userinfo2 = " + userinfo2);
		return userinfo2;
	}
}

而後經過 getBean(String id) 方法得到對象,和 xml 方式是同樣的:

package test;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import entity.Userinfo;

public class Test4 {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext context = 
				new AnnotationConfigApplicationContext("tools");
		Userinfo userinfo1 = (Userinfo)context.getBean("userinfo1");
		Userinfo userinfo2 = (Userinfo)context.getBean("userinfo2");
		System.out.println("main userinfo1 = " + userinfo1);
		System.out.println("main userinfo2 = " + userinfo2);
	}
}

運行結果:

9

使用 @ComponentScan 註解的 basePackages = 「」 建立對象,它和 <context:component-scan base-package=""> </context:component-scan> 做用是相同的,能夠進行類掃描,而且建立對象。

掃描 entity 包的類 CreateBean

package tools;

import java.util.Date;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackages = "entity")
public class CreateBean {
	@Bean
	public Date getUserinfo() {
		Date nowDate = new Date();
		System.out.println("建立 nowDate = " + nowDate);
		return nowDate;
	}
}
package entity;

import org.springframework.stereotype.Component;

@Component
public class Userinfo {
	public Userinfo() {
		System.out.println("Userinfo 構造方法執行了:" + this.hashCode());
	}
}
package test;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import tools.CreateBean;

public class Test {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext context = 
				new AnnotationConfigApplicationContext(CreateBean.class);
	}
}

運行結果:

10

咱們能夠看到 entity 下的 Userinfo 類建立了一個實例對象。

使用 @ComponentScan(basePackages = "") 掃描多個包

package tools;

import java.util.Date;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;


@Configuration
@ComponentScan(basePackages = {"entity1" , "entity2"})
public class CreateBean {
	@Bean
	public Date createDate() {
		Date nowDate = new Date();
		System.out.println("createDate " + nowDate.getTime());
		return nowDate;
	}
}
package entity1;

import org.springframework.stereotype.Component;

@Component 
public class Userinfo {
	public Userinfo() {
		System.out.println("Userinfo 構造方法執行了:" + this);
	}
}
package entity2;

import org.springframework.stereotype.Repository;

@Repository
public class Bookinfo {
	public Bookinfo() {
		System.out.println("Bookinfo 的構造方法被調用了 " + this);
	}
}
package test;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import tools.CreateBean;

public class Test4 {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext context = 
				new AnnotationConfigApplicationContext(CreateBean.class);
	}
}

運行結果:

11

使用 @ComponentScan(basePackageClasses = "") 掃描多個類

package tools;

import java.util.Date;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

import entity1.entity2.Entity2222;
import entity1.entity2.entity3.Userinfo;


@Configuration
//@ComponentScan(basePackageClasses = { Entity2222.class, Userinfo.class})
@ComponentScan(basePackageClasses = { Userinfo.class})
@ComponentScan(basePackageClasses = { Entity2222.class})

public class CreateBean {
	@Bean
	public Date createDate() {
		Date nowDate = new Date();
		System.out.println("createDate " + nowDate.getTime());
		return nowDate;
	}
}
package entity1.entity2;

import org.springframework.stereotype.Repository;

@Repository
public class Entity2222 {
	public Entity2222() {
		System.out.println("Entity2222 構造方法執行了:" + this.hashCode());
	}
}
package entity1.entity2.entity3;

import org.springframework.stereotype.Repository;

@Repository
public class Bookinfo {
	public Bookinfo() {
		System.out.println("Bookinfo 的構造方法被調用了 " + this.hashCode());
	}
}
package entity1.entity2.entity3;

import org.springframework.stereotype.Component;

@Component 
public class Userinfo {
	public Userinfo() {
		System.out.println("Userinfo 構造方法執行了:" + this.hashCode());
	}
}
package test;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import tools.CreateBean;

public class Test4 {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext context = 
				new AnnotationConfigApplicationContext(CreateBean.class);
	}
}

運行結果:

12

能夠分行寫,也能夠寫成一個數組

//@ComponentScan(basePackageClasses = { Entity2222.class, Userinfo.class})
@ComponentScan(basePackageClasses = { Userinfo.class})
@ComponentScan(basePackageClasses = { Entity2222.class})

若是隻寫 @ComponentScan, 那麼掃描的將是 @Configuration 註解配置類所在包及其子包下的全部組件。

@Component 註解表明都是一個能夠掃描的組件, @Repository 註解表明也是一個組件,通常表明的是 DAO 層的組件,也就是數據訪問層的組件。它們倆均可以被 @ComponentScan 組件掃描。

總結:這篇博客的例子基原本自 JavaEE 核心框架第二版。之前並無記錄 Spring 建立 JavaBean 的方式,因此記錄下來,方便之後學習。

代碼

相關文章
相關標籤/搜索