在 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 的方式,因此记录下来,方便之后学习。

代码

相关文章
相关标签/搜索