Spring之装配Bean三部曲
如Spring名,对于一个java开发者来说,有了Spring就等于迎来了开发的春天一样。
一、spring简单介绍
正常来说每当我们学习了解一个新的技术之类的,都会去学习了解其背景,今天咱们就简单点吧。正式开始了啊:spring就是一个简化java开发的框架!(完)
二、spring装配bean的方案
在Spring中将bean装配到容器有三种方案,去除混合搭配装备,?。
```
1. XML显示配置
2. java代码中显示配置
3. 隐式配置和自动装配
```
下面分别来讲一下这三种装配方式。
三、XML装备Bean
-
创建我们的maven工程,此步骤就不用演示了吧。
-
添加我们的相关依赖包,你不要搞成Spring-boot的依赖了啊,现在讲的是最基础的spring,而SpringBoot是一个升级版本,使用我们的开发更加简洁,简洁到你或许用不到XML配置,?,我们还是先了解一下最简单的吧,先易后难嘛,在这里我才用的Spring版本是:
<properties> <java.compiler.version>1.8</java.compiler.version> <spring.version>5.1.4.RELEASE</spring.version> </properties> <!-- Spring --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency><!--这里用不到--> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency> <dependency><!--这里用不到--> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jms</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency>
-
我们项目简单的创建完毕后(包括依赖包名等),我们创建我们第一个简单Bean-User:
public class User { private String name; private int age; public User() { } public User(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
-
创建我们的配置文件applicaitonContext.xml,并在其中配置User
<bean class="vip.zhuhailong.springother.pojo.User"/>
这就是我们最简单的配置,这样我们的User就算是装配完毕了,但是问题又来了,我该这样在程序中从容器获取到这个bean呢,此时我们反转思考一下,假如是你编码了这个框架,你该如何来暴露出这个bean让消费者来调取呢,不错就是给个唯一的标示符Id,也就是说我们在配置bean时,需要配置bean的id,如果我们没有配置,那么spring将会默认将其全限定类名来做id,我们先来测试默认ID名:
public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");//创建spring应用上下文 User user = applicationContext.getBean("vip.zhuhailong.springother.pojo.User", User.class); System.out.println(user); }
运行结果为:
User{name='null', age=0}
从结果来看,获得的User中的属性都是默认的初始化值,并没有被我们初始化,下面我们来具体在XML配置初始化User,且不使用默认的ID,为其配置id,通常我们用其类名且第一个字母小些来作为id:
<?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 class="vip.zhuhailong.springother.pojo.User" id="user">
<constructor-arg name="name" value="User"/>
<constructor-arg name="age" value="1"/>
</bean>
<!--<bean class="vip.zhuhailong.springother.pojo.User" id="user">-->
<!--<property name="name" value="User"/>-->
<!--<property name="age" value="1"/>-->
<!--</bean>-->
<!--<bean class="vip.zhuhailong.springother.pojo.User" id="user" init-method="init"/>-->
</beans>
上述的配置中,还添加了一些其他的xml初始化的配置方式,第一种是通过构造方法来配置属性值,第二种是通过直接配置属性值的方式来配置,第三种方式是指定初始化方法来初始化Bean,为此我们在User类中添加方法:
public void init() {
setName("User");
setAge(1);
}
我们更改获取bean时的id为“user”:
public class OtherMain {
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
User user = applicationContext.getBean("user", User.class);
System.out.println(user);
}
}
测试结果为:User{name='User', age=1}
,这样我们的Bean就获取到相应的属性了。
有的童鞋肯定问了,在不同的服务场景中可能都会应用到User-bean,那么在不同场景中获取到的都是同一个Bean吗?我们注释掉User中重写的toString方法来测试一下:
public class OtherMain {
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
User user1 = applicationContext.getBean("user", User.class);
User user2 = applicationContext.getBean("user", User.class);
System.out.println(user1);
System.out.println(user2);
}
}
运行结果:
vip.zhuhailong.springother.pojo.User@335eadca
vip.zhuhailong.springother.pojo.User@335eadca
从结果来看,两个User是同一个,在Spring中在装配bean时,在未指定scop时,默认使用的是单例,所以无论在那里获取User-bean,都会是同一个,现在我们需求是不需要单例,如下:
<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 class="vip.zhuhailong.springother.pojo.User" id="user" scope="prototype">
<constructor-arg name="name" value="User"/>
<constructor-arg name="age" value="1"/>
</bean>
<!--<bean class="vip.zhuhailong.springother.pojo.User" id="user">-->
<!--<property name="name" value="User"/>-->
<!--<property name="age" value="1"/>-->
<!--</bean>-->
<!--<bean class="vip.zhuhailong.springother.pojo.User" id="user" init-method="init"/>-->
</beans>
测试结果为:
vip.zhuhailong.springother.pojo.User@18eed359
vip.zhuhailong.springother.pojo.User@3e9b1010
在指定scope为prototype时,每当获取User-bean时,spring都会为我们生成一个新的User-bean。
当然还可以为其配置List 、set等集合,或者是引入其他的bean来初始化需要配置的bean,由于主要讲述配置方式,不再详细述说。
四、java代码装配bean
- 创建BeanConfig类,并加上注解@Configuration来标示此类为配置类
- 创建生成对应bean的方法,并加上注解@bean,通常默认将java代码配置类中方法名作为对应bean的id,也可以在@bean中指定bean的id;
我们先不指定固定id测试:@Configuration public class BeanConfig { @Bean public User user() { User user = new User(); user.setName("User"); user.setAge(1); return user; } }
测试结果:public class OtherMain { public static void main(String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanConfig.class); User user = applicationContext.getBean("user", User.class); System.out.println(user); } }
User{name='User', age=1}
;若指定Id,配置类为:
测试类:@Configuration public class BeanConfig { @Bean("specialUser") public User user() { User user = new User(); user.setName("User"); user.setAge(1); return user; } }
测试结果为:public class OtherMain { public static void main(String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanConfig.class); User user = applicationContext.getBean("specialUser", User.class); System.out.println(user); } }
User{name='User', age=1}
,同XML配置一样我们同样可以配置Bean的scope,在为指定Bean的scope情况下,默认为单例,若要指定scope,则增加注解:@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
这样每次注入依赖User时都会生成新的User。
五、自动化装配bean
-
同样创建UserConfig类,加上@Configuration注解告诉Spring这是一个配置类,再加上@ComponentScan注解,在未指定扫描包时,Spring会在当前配置类所在的包及其子包中的扫描装备带有@Component注解的类;若指定扫描包如:
@ComponentScan(basePackages = "path")
,Spring将会扫描path包中和其子目录下带有@Component注解的类;当然spring还提供另一种方式来配置扫描的类路径,即:@ComponentScan(basePackageClasses = 类.class)
,这样Spring将会扫描指定类的路径和其子包路径下的带有@Component, @Repository, @Service, @Controller或者已经声明过@Component自定义注解标记的组件,当前@ComponentScan或者@ComponentScans
还有很多其他的功能这里不在叙述来,配置类如下:@Configuration @Configuration @ComponentScan 或者@ComponentScan(basePackages = "vip.zhuhailong.springother.pojo") 或者@ComponentScan(basePackageClasses = BeanConfig.class) public class BeanConfig { }
-
在我们User类上增添@Component注解;为了更清晰显示我们的装配结果,我们对User通过注解进行初始化,我们可以在注解@Component中指定固定的id如:
@Component("AutoConfigUserId")
;若不指定id,则会使用类名的第一个字母小些作为id;当然在我们未指定Scope的情况此Component组件为单例,要想指定Scope,同java代码配置一样,通过注解@scope来指定模式,此处不在演示,User配置如下:@Component public class User { @Value("ComponentUserName") private String name; @Value("100000000") private int age; public User() { } public User(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + '}'; } public void init() { setName("User"); setAge(1); } }
-
测试我们的自动装配方式:
public class OtherMain { public static void main(String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanConfig.class); User user = applicationContext.getBean("user", User.class); System.out.println(user); } }
测试结果:
User{name='ComponentUserName', age=100000000}
-
补充:我们也可以不编码BeanConfig来扫描@Component组件,可以通过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: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="vip.zhuhailong.springother"/> </beans>
测试类为:
public class OtherMain { public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:*applicationContext*.xml"); User user = applicationContext.getBean("user", User.class); System.out.println(user); } }
运行结果为:
User{name='ComponentUserName', age=100000000}
本篇介绍Spring装配Bean的三种方式就到此为止,下一篇我们将进一步详细介绍Spring装备中的一些互相依赖注入及一下复杂的装配属性。谢谢大家,如有不对的地方还请大家指出必有重谢!