SpringBean实例化的方法
依赖关系注入使用配置的方式,而不是写在固定的代码里,从而实现系统的解耦。构造器注入和设置值注入是我们在开发中比较常见的两种注入方法。Spring官方推荐的是使用构造器注入的方法,而且对于一些第三方没有暴露setter方法,就只能 使用构造器进行注入了。本文以一个用户服务类(UserService)和用户的数据持久类(UserDao)为例来进行依赖注入的介绍。
1. 构造函数注入
在Bean的配置中,使用constructor-arg的字元素配置依赖的对象,对应的Bean类需要具备对应参数的构造函数。容器反射调用带参数的构造函数进行依赖对象的初始化。
public class UserDao{
public void add(User user){
System.out.println("Insert User to DB Table :" + user.getName());
}
}
在UserService中定义一个带有UserDao参数的构造函数,并在add()方法中调用Userdao的添加用户方法
public class UserService{
private UserDao userDao;
public UserService(UserDao userDao){
this.userDao = userDao;
}
public void add(String userName){
User user = new User();
user.setId(userName);
userDao.add(user);
}
}
到这里,和一般类的定义并没有什么区别。如果在另一个类中需要调用UserService的add()方法,传统的开发方式是先新建一个Userdao实例,再将这个实例作为参数新建一个UserService实力。使用Spring容器,UserDao的依赖直接在XML中配置,不需要在代码中显式的进行传递。
在Spring配置文件增加UserDao和UserService的配置,其中,在UserService增加constructor-arg配置子元素对应到构造函数的参数,在ref子元素的bean属性中设置依赖bean的id。XML配置如下:
<bean id = "userDao" class = "cn.ssm.UserDao" />
<bean id = "userService" class = "cn.ssm.UserService">
<constructor-arg ref = "userDao" />
</bean>
注意:userDao和userService在配置文件中的先后顺序并没有特定要求
2. 设置值注入
设置值注入使用的是属性的setter方法来注入依赖对象。使用setter方法设置依赖也是传统开发中较为常见的方式,使用Spring容器注入也不需要显式地调用setter方法,仅需要进行配置,由容器完成注入。
public class UserService{
private UserDao userDao;
public void setUserDao{
this.userDao = userDao;
}
public void add(String userName){
User user = new User();
user.setName(userName);
userDao.add(user);
}
}
在配置文件中使用<bean> 元素的property子元素注入依赖对象,name对应bean类中的属性名,ref设置为依赖bean的id。
<bean id="userService" class = "cn.ssm.UserService">
<property name = "userDao" ref = "userDao" />
</bean>
由容器负责类对象的创建并对这些对象的生命周期进行管理,对象的依赖关系基于配置的方式进行注入,可以很大程度降低系统的耦合度。总结:容器实例Bean,配置要先行,依赖控制转,系统耦合散
3. Bean更多实例化的方法
3.1 静态内部类
内部类是在类的内部定义的另一个类,静态内部类是内部类的一种,是使用static关键字修饰的内部类,可以通过外部类名.静态内部类名 的方式进行调用。
public class OutClass{
static class InnerClass{
public void innnerMethod(){
System.out.println("This is InnerClass's InnerMethod");
}
}
}
调用方式如下:
OutClass.InnerClass inner = new OutClass.InnnerClass();
inner.innerMethod();
如果要使用Spring容器来初始化和管理该内部类的实例,则可以在配置文件中做如下配置:
<bean id = "innnerObject" class = "cn.ssm.OutClass $InnerClass" />
与代码使用. 连接外部类和内部类不同,Bean的配置使用$ 来进行连接。
3.2 静态工厂法
静态工厂方法使用该类的一个静态方法返回该类的唯一静态对象。静态对象在整个应用中是唯一的,在类加载的时候产生使用“类名.静态方法”的方式引用,速度相对比较快。对于高频使用且全局唯一的某些类对象,比如配置类的实例,就可以使用这种方式。
public class StaticFactoryService{
public static StaticFactoryService = new StaticFactoryService();
public static StaticFactoryService getInstance(){
return service;
}
}
使用spring配置时,除了需要指定Bean的id和class属性之外,还要使用factory-method属性制定获取静态对象的方法。
<bean id = "staticFactoryService" class = "cn.ssm.StaticFactoryService" factory-method = "getInstace" />
注意:使用静态工厂方法配置Bean也可以配置Bean的constructor-arg元素进行构造函数参数的输入。
3.3 实例工厂方法
相对于以上静态工厂方法同一个类中获取该类的静态实例,使用另一个类作为工厂类的获取目标类的状况更为常见。将目标类实例的创建放在另一个工厂类的方法中,通过配置工厂类的Bean实例和方法得到目标类实例。
下面以Foo和InstanceFactory为例,Foo是目标类,InstanceFactory是获取Foo的工厂类。
public class Foo{}
public class InstanceFactory{
public static Foo foo = new Foo();
public Foo getFooInstance(){
return foo;
}
}
在配置文件中,需要配置工厂类的Bean和目标类。工厂类的Bean按一般配置即可,目标类的Bean配置不需要class属性,但需要使用factory-bean属性指定工厂类bean的id、使用factory-method属性指定获取对象实例的工厂类的方法。
<bean id = "instanceFactory" class = "cn.ssm.InstanceFactory" />
<bean id = "foo" factory-bean = "instaceFactory" factory-method = "getFooInstance" />
在现实状况中,工厂类一般用来对多个不同的目标类实例化,对应不同的实例化方法,相应的只需要增加对应的配置。
<bean id = "bar" factory-bean = "instaceFactory" factory-method = "getBarInstance" />
对比静态工厂方法和实例工厂方法,静态工厂方法获取实例的方法是静态的;实例工厂方法使用专门的工厂类获取实例,这个获取实例的方法可以不是静态的。一般而言,应用程序本身直接使用类名进行配置的方式较为直观和简单,以上方式主要是在整合第三方提供的获取特定对象的场景中使用。
|