一.前言


如果说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");
}
}


在springboot中进行区间查询的时候实体类的属性需要添加忽略 spring 实体类_spring





方法二.实现两个接口,自动生成方法


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" />

配置全局默认


在springboot中进行区间查询的时候实体类的属性需要添加忽略 spring 实体类_System_02



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的自动装配



在springboot中进行区间查询的时候实体类的属性需要添加忽略 spring 实体类_System_03



上一篇写到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



在springboot中进行区间查询的时候实体类的属性需要添加忽略 spring 实体类_bc_04




示例:创建一个db.txt


在springboot中进行区间查询的时候实体类的属性需要添加忽略 spring 实体类_System_05


测试代码


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的定义及注解形式


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


在springboot中进行区间查询的时候实体类的属性需要添加忽略 spring 实体类_作用域_06




在springboot中进行区间查询的时候实体类的属性需要添加忽略 spring 实体类_System_07






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的容器注解




在springboot中进行区间查询的时候实体类的属性需要添加忽略 spring 实体类_bc_08




完整实例:


    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


在springboot中进行区间查询的时候实体类的属性需要添加忽略 spring 实体类_作用域_09




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("销毁");
}
}