在 Spring中 创建 JavaBean

在 Spring中 创建 JavaBean

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

DI 的底层原理是反射技术,对 JavaBean 的属性进行赋值,从而达到 A 到 B 模块的解耦。Spring 提供 DI 容器,对需要关联的 JavaBean、不需要关联的 JavaBean 的创建、销毁都要进行统一的调度和管理。

在我们的程序中,我们将不使用 new 关键字的创建对象,而是交给 DI 容器管理生命周期,以及多个 JavaBean 之间的注入关系。从技术上说,就是使用反射将接口和实现相分离。

但在此之前,我们来看看如何使用 Spring 框架,以及几种创建 JavaBean 的方式。

1. 不使用 Spring 框架的传统方式

先创建一个 Java Project,创建一个保存操作的类 Save

package save;

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

一个测试类 Test

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:

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 的方式,所以记录下来,方便以后学习。

代码

转载于:https://my.oschina.net/oldbiwang/blog/1605643

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值