总的来说,配置bean有两个大的方向,一个是基于XML文件配置bean,如helloworld中的配置例子,另一个是使用注解装配。
先记录基于xml文件的装配。
在Spring-1的hello world例子,配置helloWorld bean的方式是:
<bean id="helloWorld" class="com.csu.hello.helloworld">
<property name="name" value="Jerry"></property>
</bean>
这种方式实际上就是 通过全类名(反射)配置。
还有两种配置方式,分别是工厂方法 和 FactoryBean。
- 工厂方法
从字面上来理解,工厂自然是一个生产产品的场所,在Spring里,我们生产bean,工厂则是生产bean 的一个类。
工厂方法又分为静态工厂方法和实例工厂方法。
(1)静态工厂方法:
直接调用某个类的静态方法,该方法返回bean实例。
在src下新建一个包com.csu.factory
在该包下新建Car.java
package com.csu.factory;
public class Car {
private String name;
private float price;
private int speed;
//全类名配置法必须带有无参构造器
public Car()
{}
//采用构造器注入方式需要带参构造器
public Car(String name, float price, int speed) {
super();
this.name = name;
this.price = price;
this.speed = speed;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed = speed;
}
@Override
public String toString() {
return "Car [name=" + name + ", price=" + price + ", speed=" + speed + "]";
}
}
接下来在该包下创建静态工厂类staticFactory.java:
package com.csu.factory;
import java.util.HashMap;
import java.util.Map;
public class staticFactory {
//此处访问控制符必须是static 因为静态方法需要访问
static Map<String, Car> cars=new HashMap<>();
//静态代码块完成初始化工作
static{
cars.put("dz", new Car("大众",200000,200));
cars.put("ft", new Car("福特",200000,200));
cars.put("bz", new Car("奔驰",200000,200));
cars.put("bm", new Car("宝马",200000,200));
}
//根据name生产bean
static Car buildCar(String name)
{
return cars.get(name);
}
}
接下写xml:
<!--注意,这里配置的实际上是car 而不是staticFactory>
<bean id="car1" class="com.csu.factory.staticFactory" factory-method="buildCar">
<constructor-arg value="dz"></constructor-arg>
</bean>
最后,在Main里写测试:
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
Car car=(Car) context.getBean("car1");
System.err.println(car);
后台可以打印出:Car [name=大众, price=200000.0, speed=200]
(2)实例工厂方法
观察上面这种工厂方法可得知,我们想获得car的实例,不用特地实例化一个staticFactory再调用buildCar方法,因为我们使用的是静态方法,可直接调用。实例化则需要先创建工厂本省,再调用工厂的方法。
package com.csu.factory;
import java.util.HashMap;
import java.util.Map;
public class instanceFactory {
private Map<String, Car> cars=null;
public instanceFactory()
{
cars=new HashMap<>();
cars.put("dz", new Car("大众",200000,200));
cars.put("ft", new Car("福特",200000,200));
cars.put("bz", new Car("奔驰",200000,200));
cars.put("bm", new Car("宝马",200000,200));
}
public Car getCar(String name) {
return this.cars.get(name);
}
private int getCar(String name, int no) {
//return new Car();
return 0;
}
}
<bean id="instance" class="com.csu.factory.instanceFactory"></bean>
<bean id="car2" factory-bean="instance" factory-method="getCar">
<constructor-arg value="dz"></constructor-arg>
</bean>
2.FactoryBean方式
这种方式,最大的特点是工厂类需要实现spring的FactoryBean接口,该接口定义了三个方法,如下:
package com.csu.factory;
import org.springframework.beans.factory.FactoryBean;
public class carFactoryBean implements FactoryBean<Car>{
private String brand;
public void setBrand(String brand) {
this.brand=brand;
}
@Override
public Car getObject() throws Exception {
// TODO Auto-generated method stub
return new Car(brand,20932,120);
}
@Override
public Class<?> getObjectType() {
// TODO Auto-generated method stub
return Car.class;
}
@Override
public boolean isSingleton() {
// TODO Auto-generated method stub
return false;
}
}
<bean id="car3" class="com.csu.factory.carFactoryBean">
<property name="brand" value="BMW"></property>
</bean>
这里虽然看起来实在配置carFactory,但实际返回的是carFactory 的getObject确定的类。
以上就是基于xml文件的配置,下面来说一说注解配置。
一说到注解,就是用一个@**加在一个字段或者方法上边就可以简单方便地完成很多事情。
工程结构:
beans-annotation.xml:
配置扫描包(可玩各种花样,比如只扫描哪里,不扫描哪里等等,具体可查手册)
<context:component-scan base-package="com.csu.annotation"></context:component-scan>
扫描annotation 以及 annotation下所有子包,只要发现带了
1 @Component 一般
2 @Repository 持久层
3 @Service 服务层
4 @ Controller 表现层
这四种注解的,IOC容器就把他们当作bean来配置,就不用自己在xml事无巨细的配置了。
比如:
package com.csu.annotation.repository;
import org.springframework.stereotype.Repository;
@Repository("userRepository")
public class UserRepositoryImpl implements UserRepository{
//UserRepository是一个自定义接口
@Override
public void save() {
// TODO Auto-generated method stub
System.out.println("save....");
}
}
public class MainAnnot {
public static void main(String[] args) {
// TODO Auto-generated method stub
ApplicationContext context=new ClassPathXmlApplicationContext("beans-annotation.xml");
//TestObject testObject=(TestObject) context.getBean("test");
//System.out.println(testObject);
UserRepository repository=(UserRepository) context.getBean("userRepository");
repository.save();
//UserController controller=(UserController) context.getBean("userController");
//controller.execute();
//UserService service=(UserService) context.getBean("userService");
//service.add();
}
}
现在有一个问题就是,这只能配置单个独立的bean,如果bean里有bean呢?
比如Controller要用定义一个service是对象并实例化,service里定义repository对象并实例化,这种关系如何实现?
这里可用@Autowire来自动装配:
package com.csu.annotation.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.csu.annotation.repository.UserRepository;
@Service
public class UserService {
@Autowired
private UserRepository repository;
public void add() {
System.out.println("service add....");
repository.save();
}
}
此处repository就可以自动装配。
最后一个问题,UserRepository 是一个接口类型,如果同时有多个类实现了该接口,这时到底该装配哪一个呢?
有两种解决办法:
(1)@Autowir下再标注一个 @Qualifier(“具体要装配的那个类名”)
(2)把字段名整得和bean名字一样。
我认为第一种更好,加一行上去标清楚,看得更清晰。