spring框架详解(二)--bean的装配

一.前言

如果说spring是一个生产商品的工厂,那么bean就是里面的商品.对商品的装配是整个流程的重要部分,那么我们从下面几个方面对bean有个更深层的理解

二.bean的作用域

当通过Spring容器创建一个Bean实例时,不仅可以完成Bean实例的实例化,还可以为Bean指定特定的作用域。Spring支持如下5种作用域:

singleton:单例模式,在整个Spring IoC容器中,使用singleton定义的Bean将只有一个实例.默认为singleton

prototype:原型模式,每次通过容器的getBean方法获取prototype定义的Bean时,都将产生一个新的Bean实例

request:对于每次HTTP请求,使用request定义的Bean都将产生一个新实例,即每次HTTP请求将会产生不同的Bean实例。只有在Web应用中使用Spring时,该作用域才有效

session:对于每次HTTP Session,使用session定义的Bean豆浆产生一个新实例。同样只有在Web应用中使用Spring时,该作用域才有效

globalsession:每个全局的HTTP Session,使用session定义的Bean都将产生一个新实例。典型情况下,仅在使用portlet context的时候有效。同样只有在Web应用中使用Spring时,该作用域才有效

三.bean的生命周期

bean的初始化与销毁的方法:
针对某个类使用
方法一.自行定义方法

<bean id="beanLifeCycle" class="com.eduask.chp.test.BeanLifeCycle" init-method="start" destroy-method="end"/>
在这里配置了两个方法,然后你在所在的类书写两个方法,如下所示
public class BeanLifeCycle {
public void start() {
	System.out.println("bean start");
}
public void  end() {
	System.out.println("bean end");
}
}

单元测试结果效果图如下










方法二.实现两个接口,自动生成方法
public class BeanLifeCycle implements InitializingBean,DisposableBean{
	public void destroy() throws Exception {
		System.out.println("初始化");
	}
	public void afterPropertiesSet() throws Exception {
		System.out.println("销毁");
	}
}

xml配置这里就直接写这个
<bean id="beanLifeCycle" class="com.eduask.chp.test.BeanLifeCycle" />

配置全局默认


public class BeanLifeCycle {
	public void defaultInit() {
		System.out.println("默认方法 初始化");
	}
	public void defaultDestroy() {
		System.out.println("默认方法  销毁");
	}
}


四.spring  awer接口

容器管理的Bean一般不需要了解容器的状态和直接使用容器,但是在某些情况下,是需要在Bean中直接对IOC容器进行操作的,这时候,就需要在Bean中设定对容器的感知。Spring IOC容器也提供了该功能,它是通过特定的Aware接口来完成的。aware接口有以下这些:

BeanNameAware,可以在Bean中得到它在IOC容器中的Bean的实例的名字。

BeanFactoryAware,可以在Bean中得到Bean所在的IOC容器,从而直接在Bean中使用IOC容器的服务。

ApplicationContextAware,可以在Bean中得到Bean所在的应用上下文,从而直接在Bean中使用上下文的服务。

MessageSourceAware,在Bean中可以得到消息源。

ApplicationEventPublisherAware,在bean中可以得到应用上下文的事件发布器,从而可以在Bean中发布应用上下文的事件。

ResourceLoaderAware,在Bean中可以得到ResourceLoader,从而在bean中使用ResourceLoader加载外部对应的Resource资源。


重点来讲下ApplicationContextAware 与BeanNameAware
 
 当一个类实现了这个接口(ApplicationContextAware)之后,这个类就可以方便获得ApplicationContext中的所有bean。换句话说,就是这个类可以直接获取spring配置文件中,所有有引用到的bean对象。
其实之前在测试类也可以通过这种形式获取这个对象
ApplicationContext app=new ClassPathXmlApplicationContext("spring-bean.xml")

现在通过实现这个接口来获取对象 ,为了测试这两个是不是同一个对象,输出两个的hashcode值
public class AppContent implements ApplicationContextAware,BeanNameAware{
	private static ApplicationContext appContext;
	private String beanName;
	public void setBeanName(String name) {
		this.beanName=name;
		System.out.println(name);
	}
	public void setApplicationContext(ApplicationContext applicationContext)
			throws BeansException {
		this.appContext=applicationContext;
		System.out.println(appContext.getBean(this.beanName).hashCode());
	}
}
单元测试
public class Junit {
	static ApplicationContext app;
	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
		app=new ClassPathXmlApplicationContext("spring-bean.xml");
	}
	@AfterClass
	public static void tearDownAfterClass() throws Exception {
		((AbstractApplicationContext) app).destroy();
	}
	@Test
	public void test() {
		System.out.println(app.getBean("appContent").hashCode());;
	}

}
最后测试结果为两个都是同一个对象

五.bean的自动装配


上一篇写到spring注入,业务层跟dao层是通过这种途径的
<bean id="testService" class="com.eduask.chp.test.TestServiceImp">  
<property name="testDao" ref="testDao"></property>  
</bean>  
<bean id="testDao" class="com.eduask.chp.test.TestDaoImp"/>

但是如果使用自动装配的话通过byName形式
在beans里加入这句话 default-autowire="byName",那么它就自动将两者绑定在一起了

constructor 是在要装配的对象调用另个对象的构造方法才能使用

六.spring Resource

为了获得文件资源的一些信息


Application 是继承ResourceLoader


示例:创建一个db.txt

测试代码
public class AppContent implements ApplicationContextAware{
	private static ApplicationContext appContext;
	public void setApplicationContext(ApplicationContext applicationContext)
			throws BeansException {
		this.appContext=applicationContext;
		Resource rs=appContext.getResource("classpath:db.txt");//这里面的地址,还可以写网址,写法:url:http://网址
		try {
			System.out.println(rs.getFilename()+"\n"+rs.contentLength());
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

七.bean的定义及注解形式

针对下面的图上的内容进行详细讲解






1.类的自动检测与bean注册
<context:annotation-config>
该标签隐式的向Spring容器注册了下面四个BeanPostProcessor:
AutowiredAnnotationBeanPostProcessor    @AutoWired
CommondAnnotationBeanPostProcessor    @Resource、@PostConstruct、@Predestory等注解
PersistenceAnnotationBeanPostProcessor   @PersistenceContext
RequiredAnnotationBeanPostProcessor.     @Required
这四个是为了我们之后使用相应的注解准备的
<context:component-scan base-package=" ">
这个<context:component-scan>除了具有<context:annotation-config>的功能之外,<context:component-scan>还可以在指定的package下扫描以及注册javabean 。
所以工作开发中一般使用后者

2.bean的定义及其作用域
例子
首先建立一个BeanTest的测试类
package com.eduask.chp.bean;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Scope//作用域
@Component("bean")//自定义类的名字
public class BeanTest {
public void show() {
	System.out.println("BeanTest:=="+this.hashCode());
}
}
然后在xml包扫描
context:component-scan base-package="com.eduask.chp.bean"></context:component-scan>

接着单元测试
@Test
    public void test() {
    BeanTest bean=(BeanTest) app.getBean("bean");//这里的bean是@Component("bean"),如果不定义那么就是类名的首字母小写
    bean.show();
    BeanTest bean1=(BeanTest) app.getBean("bean");
    bean1.show();
进行两次创建bean对象,是为了测试scope的作用域,scope的默认是单例,也就是只创建一个容器,所以测试结果的hashcode是一样的,但是如果将scope后改为@Scope("prototype"),那么每次getBean就会创建一个新的实例

3.@Required注解
Spring 配置文件中 dependency-check 依赖检查的灵活性不够,并不能满足我们所有的需求
Spring还提供一种更加灵活的检查方式 
@Required注解检查 但他只检查属性是否已经设置而不会测试属性是否非空

这个注解只能设置在set方法之上

4.@Autowired注解
也就是自动注入绑定,项目一般分dao数据库操作层,service业务层,mvc控制层,autowired可以方便的将三者联系在一起
实例:
dao层:
@Repository
public interface ApplyDao {						
	@Insert("insert into tb_invitejob values(null,#{name},#{sex},#{age},#{born},#{job},#{specialty},"
			+ "#{experience},#{teachSchool},#{afterSchool},#{tel},#{address},#{createtime},#{content},#{isstock})")
	public void addApply(Apply apply);//添加应聘信息
}

service层实现类:
  
@Service
public class ApplyServiceImp implements ApplyService {
@Autowired
private ApplyDao applyDao;
@Override
public void addApply(Apply apply) {
	applyDao.addApply(apply);//添加应聘者信息
}
	
}

controller层
   
@Controller
@RequestMapping("/view")
public class ApplyController {
@Autowired
private ApplyService applyService;
@RequestMapping("/inviteJob.do")
public String addApply(Apply apply) {
	applyService.addApply(apply);
	return "main";
	
}
}
你会发现都有一个@Autowired,这个注解在包扫描的时候已经可以使用了
以上是注入到单个接口或者类中,它还能将类或接口注入到list和map中
@Autowired
private List<Service> list;//将service接口注入到list中
你可以在实现Service接口的类加@order()设置先后

@Autowired
private Map<String, Object>;//将service接口注入到map中

遍历的是继承这个接口的类

结合@Qualifier注解
由于有时候自动绑定的接口有多个实现类,这时候就要用@Qualfier()指定相应的接口

@Component
public class Invoker {
@Autowired
@Qualifier("oneService")//注意:开头首字母要小写
private Service service;
public void show() {
System.out.println(service.getClass().getName());
}
}



5.基于java的容器注解



完整实例:
    store接口
public interface Store {
}
   它的实现类StringStore
public class StringStore implements Store{
public void init() {
	System.out.println("开始初始化");
}
public void destroy() {
	System.out.println("开始销毁");
}
}

它的配置类StoreConfig
 
//配置bean
@Configuration
public class StoreConfig {
@Bean(name="store",initMethod="init",destroyMethod="destroy")//这里面是配置bean的id,初始化方法与销毁放方法
 public Store getStringStore() {
	return new StringStore();
}
}
注意:如果没指定name,那么它的bean id是方法名,而不是类名

如何读取数据库配置文件的内容?
JDBC.properties  
   jdbc.driver=com.mysql.jdbc.Driver
   jdbc.url=jdbc:mysql://localhost:3306/empmanager
   jdbc.username=root
   jdbc.password=root
xml形式配置:
 
<!--配置数据源 -->
<context:property-placeholder location="classpath:JDBC.properties"/>
<bean id="ds" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="driverClass" value="${jdbc.driver}" />
    <property name="jdbcUrl" value="${jdbc.url}" />
    <property name="user" value="${jdbc.username}"/>
    <property name="password" value="${jdbc.password}" />
</bean>
这里需要c3p0的所需jar包
<dependency>     
   <groupId>com.mchange</groupId>
   <artifactId>c3p0</artifactId>  
   <version>0.9.5.2</version> 
   </dependency>

6.基于泛型的自动装配
接口Store<T>
两个实现类StringStore,IntStore


7.@Resource注解


@Resource注解,@Autowired,@inject的区别:
@Autowire默认按照类型装配,默认情况下它要求依赖对象必须存在如果允许为null,可以设置它required属性为false,如果我们想使用按照名称装配,可以结合@Qualifier注解一起使用;

@Resource默认按照名称装配,当找不到与名称匹配的bean才会按照类型装配,可以通过name属性指定,如果没有指定name属性,当注解标注在字段上,即默认取字段的名称作为bean名称寻找依赖对象,当注解标注在属性的setter方法上,即默认取属性名作为bean名称寻找依赖对象.

JSR-330的@Inject 为了统一各种依赖注入框架的编程模型,JCP最近发布了java依赖注入规范,JCP将其称为JSR-330,@Inject注解是JSR-330的核心部件。该注解几乎可以完全替代Spring的@Autowired注解。所以除了使用Spring特定的@Autowired注解,我们可以选择@Inject。 和@Autowired一个,@Inject可以用来自动装配属性、方法和构造器;与@Autowired不同的是,@Inject没有required属性。因此@Inject注解注入的依赖关系必须存在,否则报异常。 与@Autowired一样,@Inject有自己限定的方法,即处理限定歧义性的依赖, 与@Named("xxName")一起用,可以指定具体的哪一个
注:实际上,@Named注解就是一个使用@Qualifier注解所标注的注解

注意:如果没有指定name属性,并且按照默认的名称仍然找不到依赖的对象时候,会回退到按照类型装配,但一旦指定了name属性,就只能按照名称装配了

8.关于初始化与销毁的注解

之前上面xml配置的时候已经说明了初始化与销毁,注解形式如下:
@Service
public class JrsServiceImp implements JrsService{
@Resource
private JrsDao jrsDao;
	public void saveService() {
		jrsDao.saveDao();
		System.out.println("数据已保存");
	}
@PostConstruct
public void init() {
	System.out.println("初始化");
}
@PreDestroy
public void destroy() {
	System.out.println("销毁");
}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值