您的位置:首页 > 编程语言 > Java开发

Spring4深入理解IOC&DI04----Bean配置方式(全类名,工厂方法,FactoryBean),配置形式(基于XML和注解),泛型依赖注入

2016-09-16 19:13 1491 查看
参考代码下载github:https://github.com/changwensir/java-ee/tree/master/spring4

一、Bean的配置方式

Bean 的配置方式:通过全类名(反射)、通过工厂方法(静态工厂方法 & 实例工厂方法)、FactoryBean

1-1.通过静态工厂方式配置Bean

--•调用静态工厂方法创建Bean是将对象创建的过程封装到静态方法中.当客户端需要对象时,只需要简单地调用静态方法,而不同关心创建对象的细节.
--•要声明通过静态方法创建的 Bean,需要在Bean的class属性里指定拥有该工厂的方法的类,同时在factory-method属性里指定工厂方法的名称.最后,使用<constrctor-arg>元素为该方法传递方法参数.
1-2.通过实例工厂方式配置Bean

•实例工厂方法:
将对象的创建过程封装到另外一个对象实例的方法里.当客户端需要请求对象时,只需要简单的调用该实例方法而不需要关心对象的创建细节.
•要声明通过实例工厂方法创建的 Bean
–在 bean
的factory-bean属性里指定拥有该工厂方法的Bean
–在 factory-method属性里指定该工厂方法的名称
–使用 construtor-arg元素为工厂方法传递方法参数

/**
* InstanceCarFactory:实例工厂方法
* 实例工厂的方法,即需要先创建工厂本身,再调用工厂的实例方法来返回bean的实例
*
* @author Lcw 2015/11/12
*/
public class InstanceCarFactory {
private Map<String, Car> cars = null;

public InstanceCarFactory() {
cars = new HashMap<String, Car>();
cars.put("audi", new Car("audi", 500000));
cars.put("ford", new Car("ford", 600000));
}

public Car getCar(String brand) {
return cars.get(brand);
}
}


/**
* StaticCarFactory:静态工厂方法:直接调用某一个类的静态方法就可以返回Bean实例
*/
public class StaticCarFactory {
private static Map<String , Car> cars = new HashMap<String, Car>();

static {
cars.put("audi",new Car("audi", 30000));
cars.put("ford",new Car("ford", 40000));
}

//静态工厂方法: 注意:要在配置文件XML里配置Car而不是StaticCarFactory
public static Car getCar(String name) {
return cars.get(name);
}
}
<?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 http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> 
<!--通过静态工厂方法来配置bean, 注意不是配置静态工厂方法实例,而是配置bean实例-->
<!--factory-method: 指向静态工厂方法的名字
constructor-arg:如果工厂方法需要传入参数,则使用constructor-arg来配置参数-->
<bean id="car1" class="Spring4_IOC.bean.factory.StaticCarFactory"
factory-method="getCar">
<constructor-arg value="audi"/>
</bean>

<!--配置实例工厂的实例-->
<bean id="carFactory" class="Spring4_IOC.bean.factory.InstanceCarFactory"/>
<!-- 通过实例工厂方法来配置bean-->
<bean id="car2" factory-bean="carFactory" factory-method="getCar">
<constructor-arg value="ford"/>
</bean>
</beans>
/**
* Bean 的配置方式:-、通过全类名(反射);二、通过工厂方法(静态工厂方法 & 实例工厂方法);三、FactoryBean
*
* 静态工厂方法:直接调用某一个类的静态方法就可以返回Bean实例
* 实例工厂方法:实例工厂的方法,即需要先创建工厂本身,再调用工厂的实例方法来返回bean的实例
*/
@Test
public void testStaticFactory() {
ApplicationContext ctx = new ClassPathXmlApplicationContext("Spring4_IOC/beans-factory.xml");
//测试静态工厂方法
Car car1 = (Car) ctx.getBean("car1");
System.out.println(car1);

//实例工厂方法
Car car2 = (Car) ctx.getBean("car2");
System.out.println(car2);
}
1-3.实现 FactoryBean 接口在 Spring IOC 容器中配置 Bean

•Spring 中有两种类型的Bean,一种是普通Bean,另一种是工厂Bean,即FactoryBean.
•工厂 Bean 跟普通Bean不同,其返回的对象不是指定类的一个实例,其返回的是该工厂Bean的getObject方法所返回的对象



/**
* CarFactoryBean:自定义的factoryBean需要实现FactoryBean
*/
public class CarFactoryBean implements FactoryBean<Car> {
private String brand;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}

public CarFactoryBean() {
}
//下面是三个实现方法
//返回bean的对象
public Car getObject() throws Exception {
return new Car("BMW" , 500000);
}

//返回bean的类型Class<?>  中?表示一个未知的类
public Class<?> getObjectType() {
return Car.class;
}

public boolean isSingleton() {
return true;
}
}
<?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 http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> 
<!--
通过factoryBean来配置Bean的实例
class:指向FactoryBean的全类名
property:配置FactoryBean的属性

但实际返回的实例确是FactoryBean的getObject()返回的实例-->
<bean id="car" class="Spring4_IOC.bean.CarFactoryBean">
<property name="brand" value="BMW"/>
</bean>
</beans>
/**
* Bean 的配置方式:-、通过全类名(反射);二、通过工厂方法(静态工厂方法 & 实例工厂方法);三、FactoryBean
*
* 测试FactoryBean
* Spring 中有两种类型的 Bean, 一种是普通Bean, 另一种是工厂Bean, 即FactoryBean
*/
@Test
public void testFactoryBean() {
ApplicationContext ctx = new ClassPathXmlApplicationContext("Spring4_IOC/beans-beanFactory.xml");
Car car = (Car) ctx.getBean("car");  //注意这个在类是Car!
System.out.println(car);
}

二、Bean的配置形式

配置形式:基于 XML 文件的方式;基于注解的方式(基于注解配置 Bean;基于注解来装配 Bean 的属性)

在 classpath 中扫描组件

•组件扫描(componentscanning): Spring能够从classpath下自动扫描,侦测和实例化具有特定注解的组件.
•特定组件包括:
–@Component: 基本注解,标识了一个受Spring管理的组件
–@Respository:标识持久层组件
–@Service: 标识服务层(业务层)组件
–@Controller: 标识表现层组件
•对于扫描到的组件,Spring有默认的命名策略:使用非限定类名,第一个字母小写.也可以在注解中通过value属性值标识组件的名称
•当在组件类上使用了特定的注解之后,还需要在Spring的配置文件中声明<context:component-scan>:
–base-package 属性指定一个需要扫描的基类包,Spring容器将会扫描这个基类包里及其子包中的所有类.
–当需要扫描多个包时,
可以使用逗号分隔.
–如果仅希望扫描特定的类而非基包下的所有类,可使用 resource-pattern属性过滤特定的类,示例:
–<context:include-filter>子节点表示要包含的目标类
–<context:exclude-filter>子节点表示要排除在外的目标类
–<context:component-scan>下可以拥有若干个<context:include-filter>和<context:exclude-filter>子节点

以下 类那放在这个文件下Spring4_IOC.annotation

@Component
public class TestObject {
}
respository接口跟实现类

public interface UserRepository {
void save();
}
//接口实现一般用接口名
@Repository("userRepository")
public class UserRepositoryImpl implements UserRepository {
public void save() {
System.out.println("UserRepository Save...");
}
}
Service层跟controller

@Service
public class UserService {
//@Autowired(required=false) //如果没有这个类,输出为null
 @Autowired
private UserRepository userRepository;

public void add() {
System.out.println("UserService add...");
userRepository.save();
}
}
@Controller
public class UserController {
@Autowired
private UserService userService;
public void execute() {
System.out.println("UserController execute...");
userService.add();
}
}
<?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"> 
<!--指定Spring IOC容器扫描的包-->
<!--可以通过resource-pattern指定扫描的资源-->
<!--<context:component-scan base-package="Spring4_IOC.annotation"
resource-pattern="repository/*.class"></context:component-scan>-->

<!--exclude-filter: 子节点指定排除哪些指定表达式的组件-->
<!--include-filter:子节点指定包含哪些表达式的组件,该子节点需要use-default-filters="false"配合使用-->
<context:component-scan base-package="Spring4_IOC.annotation" >
<!--<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>-->
<!--<context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>-->

<!--<context:exclude-filter type="assignable" expression="com.changwen.spring4.annotation.repository.UserRepository"/>-->
<!--<context:include-filter type="assignable" expression="com.changwen.spring4.annotation.repository.UserRepository"/>-->
</context:component-scan>
</beans>
@Test
public void testAnnotation() {
ApplicationContext ctx = new ClassPathXmlApplicationContext("Spring4_IOC/beans-annotation.xml");

TestObject to = (TestObject) ctx.getBean("testObject");
System.out.println(to);

//类UserController第一个字母小写 userController
UserController userController = (UserController) ctx.getBean("userController");
System.out.println(userController);
userController.execute();

UserService userService = (UserService) ctx.getBean("userService");
System.out.println(userService);

UserRepository userRepository = (UserRepository) ctx.getBean("userRepository");
System.out.println(userRepository);
}
<context:include-filter>和<context:exclude-filter>子节点支持多种类型的过滤表达式



2-1.组件装配

•<context:component-scan>元素还会自动注册AutowiredAnnotationBeanPostProcessor实例,该实例可以自动装配具有@Autowired和@Resource、@Inject注解的属性.
1).使用 @Autowired自动装配Bean

•@Autowired注解自动装配具有兼容类型的单个Bean属性
–构造器,普通字段(即使是非public),一切具有参数的方法都可以应用@Authwired注解
–默认情况下,所有使用@Authwired注解的属性都需要被设置.当Spring找不到匹配的Bean装配属性时,会抛出异常,若某一属性允许不被设置,可以设置@Authwired注解的required属性为false
–默认情况下,当IOC容器里存在多个类型兼容的Bean时,通过类型的自动装配将无法工作.此时可以在@Qualifier注解里提供Bean的名称.Spring允许对方法的入参标注@Qualifiter已指定注入Bean的名称
–@Authwired注解也可以应用在数组类型的属性上,此时Spring将会把所有匹配的Bean进行自动装配.
–@Authwired注解也可以应用在集合属性上,此时Spring读取该集合的类型信息,然后自动装配所有与之兼容的Bean.
–@Authwired注解用在java.util.Map上时,若该Map的键值为String,那么Spring将自动装配与之Map值类型兼容的Bean,此时Bean的名称作为键值


2).使用 @Resource或@Inject自动装配Bean


•Spring 还支持
@Resource和@Inject注解,这两个注解和@Autowired注解的功用类似
•@Resource 注解要求提供一个Bean名称的属性,若该属性为空,则自动采用标注处的变量或方法名作为Bean的名称
•@Inject 和
@Autowired注解一样也是按类型匹配注入的Bean,但没有reqired属性
•建议使用 @Autowired注解

三、泛型依赖注入

•Spring 4.x 中可以为子类注入子类对应的泛型类型的成员变量的引用



public class BaseRepository<T> {
}
public class BaseService<T> {
@Autowired
protected BaseRepository<T> repository;

public void add() {
System.out.println("add...");
System.out.println(repository);
}
}
@Service
public class UserService extends BaseService<User> {
}
public class User {
private String userName;
private List<Car> cars;
private String wifeName;

public String getWifeName() {
return wifeName;
}

public void setWifeName(String wifeName) {
System.out.println("setWifhName: " + wifeName);
this.wifeName = wifeName;
}

public String getUserName() {
return userName;
}

public void setUserName(String userName) {
this.userName = userName;
}

public List<Car> getCars() {
return cars;
}

public void setCars(List<Car> cars) {
this.cars = cars;
}

public User() {
System.out.println("User's Construtor...");
}

@Override
public String toString() {
return "User [userName=" + userName + ", cars=" + cars + "]";
}

public void init(){
System.out.println("init method...");
}

public void destroy(){
System.out.println("destroy method...");
}

}
@Repository
public class UserRepository extends BaseRepository<User>{
}
配置文件

<?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/util http://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> 
<context:component-scan base-package="Spring4_IOC.di">

</context:component-scan>
</beans>
/**
* Spring 4.x 新特性:泛型依赖注入
*/
@Test
public void testDI() {
ApplicationContext ctx = new ClassPathXmlApplicationContext("Spring4_IOC/beans-generic.xml");
Spring4_IOC.di.UserService userService = (Spring4_IOC.di.UserService) ctx.getBean("userService");
System.out.println(userService);
userService.add();
}

Spring4_IOC.di.UserService@225a8897

add...

Spring4_IOC.di.UserRepository@65bd831f
整合多个配置文件

•Spring 允许通过
<import>将多个配置文件引入到一个文件中,进行配置文件的集成。这样在启动Spring容器时,仅需要指定这个合并好的配置文件就可以。
•import元素的resource属性支持Spring的标准的路径资源

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐