再看Spring框架篇【一】-------IoC

 

首先总结一下,总结一下Spring框架包含哪些内容

1.Spring框架的基本概念

2.IoC控制反转

3.AOP面向切面编程

4.Spring的DAO以及其事务

Spring整合SSH/SSM就不在这个范畴了。

用目录来看,就是这样的了。

后面的AOP和事务我就放在后面的博客文章里面了。

Spring的定义:

Spring是一个容器,管理系统里面的所有bean和依赖关系。这个框架是用来降低耦合度,它对不同的代码采用不同的解耦方式,对于主业务逻辑之间的交叉耦合,使用IoC来实现。对于系统级别的逻辑交叉,使用AOP来实现解耦。

Spring体系结构图:

现在在spring官方网站已经看不到这个图了,不知道是不是我没有找到的原因。

Spring的特点

 ①非侵入式

 ②容器 管理对象的生命周期,对象与对象之间的关系。可以通过配置文件,来定义对象, 以及配置与其他的依赖关系。

③ IoC 控制反转,即创建被调用者的实例不是有调用者完成的,而是由Spring容器完成。

④AOP 面向切面编程,是一种编程思想。是对OOP的补充。分离应用的业务逻辑与系统级服务进行开发,应用对象只实现它们应该做的完成业务逻辑而已。

IoC

控制反转(IoC) 指将传统上由程序代码直接操控的对象调用权交给容器,通过容器来实现对象的装配和管理。控制反转就是对对象控制权的转移,从程序代码本身反转到了外部容器。

IoC 是一个概念,是一种思想,其实现方式多种多样。当前比较流行的实现方式有两种:

依赖注入和依赖查找。依赖注入方式应用更为广泛。

Ø 依赖查找:Dependency Lookup ,DL,容器提供回调接口和上下文环境给组件,程序代

码则需要提供具体的查找方式。比较典型的是依赖于 JNDI 系统的查找。

依赖注入:Dependency Injection,DI,程序代码不做定位查询,这些工作由容器自行完

成。

依赖注入 DI 是指程序运行过程中,若需要调用另一个对象协助时,无须在代码中创建

被调用者,而是依赖于外部容器,由外部容器创建后传递给程序。

Spring 的依赖注入对调用者与被调用者几乎没有任何要求,完全支持 POJO 之间依赖关系的管理。

依赖注入是目前最优秀的解耦方式。依赖注入让 Spring 的 Bean 之间以配置文件的方式组织在一起,而不是以硬编码的方式耦合在一起的。

Spring第一个程序

下面这个程序就拿传统的new对象的方式和使用spring的方式做了一个比较

项目结构图:

新建一个java project

导入jar

首先定义接口

public interface UserService {
	public void add();
	
	public void update();
	

}

再写实现类

public class UserServiceImpl implements UserService {

	@Override
	public void add() {
		
	}

	@Override
	public void update() {
		
	}
	
}

测试类:

public class Test {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		/**
		 * 传统的方式如果想要调用add update方法的话就必须new一个对象出来 如下
		 */
		UserService userService=new UserServiceImpl();
		userService.update();
		userService.add();
		

	}

}

这就是传统的方式了,要调用UserServiceImpl里面的update和add方法就必须new一个对象。再来看看spring的实现方式

创建一个java project

导入上面的jar到lib 并将jar 添加到环境里面去。

接口:

public interface ISomeService {
	String doFirst();
	void duSecond();

}

实现类:

public class SomeServiceImpl implements ISomeService {

	
	public SomeServiceImpl() {
		System.out.println("对象创建了。。。。。");
	}

	@Override
	public String doFirst() {
		System.out.println("执行doFirst方法");
		return "abcd";
	}

	@Override
	public void duSecond() {
		System.out.println("执行读second方法");

	}

}

测试类:

public class MyTest {

@Test

public void test01() {

ISomeService service = new SomeServiceImpl();

service.doFirst();

service.duSecond();



}

@Test

public void test02() {

//创建容器对象

//这里的配置文件存放在项目的src下

ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

ISomeService service=(ISomeService)ac.getBean("SomeService");

service.doFirst();

service.duSecond();



}

public void test03() {

//这里的配置文件存放在项目的根下   具体的路径 如:d:applicationContext.xml

ApplicationContext ac = new FileSystemXmlApplicationContext("applicationContext.xml");

ISomeService service=(ISomeService)ac.getBean("SomeService");

service.doFirst();

service.duSecond();



}

@SuppressWarnings("deprecation")

@Test

public void test04() {

//这个容器中的对象不是在容器初始化时创建的,而是在真正使用时创建的。

BeanFactory bf = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));

ISomeService service=(ISomeService)bf.getBean("SomeService");

service.doFirst();

service.duSecond();

}

}

applicationContext.xml

<?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">
        <!-- 注册service对象 等同于ISomeService service = new SomeServiceImpl();
       	 这个对象是再spring容器被初始化时候创建的。
         -->
		<bean id="SomeService" class="com.liuz.service.SomeServiceImpl"></bean>
</beans>

执行的效果就不粘贴上来了,自己复制代码跑一遍就知道了。

总结一下

/**

 * 使用BeanFactory创建bean和使用ClassPathXmlApplicationContext、FileSystemXmlApplicationContext

 * 创建bean方式的比较:

 * 1.BeanFactory是在真正要使用的时候再创建对象,相对于内存的消耗来说要好,但执行效率慢

 * 2.ClassPathXmlApplicationContext、FileSystemXmlApplicationContext在容器初始化的时候就创建了,内存消耗高,但执行效率快

 * 相对来说现在我们的内存很大,而web项目对执行效率有要求。

 */

下一个知识点就是Spring的bean的装配,也就是对象的创建

Bean 的装配,即 Bean 对象的创建。容器根据代码要求创建 Bean 对象后再传递给代码

的过程,称为 Bean 的装配。

首先我们知道,我们在java代码里面

ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

通过这一句,我们就完成了spring容器的初始化,那么这一句spring容器到底是怎么进行初始化的呢?底层做了哪些事情?

下面是bean的类图

从该继承体系可以看出:

1.       BeanFactory 是一个 bean 工厂的最基本定义,里面包含了一个 bean 工厂的几个最基本的方 法,getBean(…) 、 containsBean(…) 等 ,是一个很纯粹的bean工厂,不关注资源、资源位置、事件等。 ApplicationContext 是一个容器的最基本接口定义,它继承了 BeanFactory, 拥有工厂的基本方法。同时继承了 ApplicationEventPublisher 、 MessageSource 、 ResourcePatternResolver 等接口, 使其 定义了一些额外的功能,如资源、事件等这些额外的功能。

2.      AbstractBeanFactory 和 AbstractAutowireCapableBeanFactory 是两个模 板抽象工厂类。AbstractBeanFactory 提供了 bean 工厂的抽象基类,同时提供 了 ConfigurableBeanFactory 的完整实现。AbstractAutowireCapableBeanFactory 是继承 了 AbstractBeanFactory 的抽象工厂,里面提供了 bean 创建的支持,包括 bean 的创建、依赖注入、检查等等功能,是一个 核心的 bean 工厂基类。

3.ClassPathXmlApplicationContext之 所以拥有 bean 工厂的功能是通过持有一个真正的 bean 工厂DefaultListableBeanFactory 的实例,并通过 代理 该工厂完成。

  1.  ClassPathXmlApplicationContext 的初始化过程是对本身容器的初始化同时也是对其持有的DefaultListableBeanFactory 的初始化。

容器初始化过程:

我们知道在spring中BeanDefinition很重要。因为Bean的创建是基于它的。容器AbstractApplicationContext中有个方法是refresh()这个里面包含了整个Bean的初始化流程实现过程,如果我们需要自己写一个ClassPathXmlApplicationContext类的话我们可以继承这个类,下面贴段这个方法的代码:

public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
            prepareBeanFactory(beanFactory);

            try {
                // Allows post-processing of the bean factory in context subclasses.
                postProcessBeanFactory(beanFactory);

                // Invoke factory processors registered as beans in the context.
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
                initMessageSource();

                // Initialize event multicaster for this context.
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.
                onRefresh();

                // Check for listener beans and register them.
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.
                finishRefresh();
            }

            catch (BeansException ex) {
                // Destroy already created singletons to avoid dangling resources.
                beanFactory.destroySingletons();

                // Reset 'active' flag.
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            }
        }
    }

如上代码加上图片就是整个Bean的初始化过程。我们知道Bean有可以配置单列以及懒加载形式。在初始化的过程中,我们也能很好的观察到这个过程的实现。

在AbstractBeanFactory中定义了getBean()方法,而它又调用doGetBean().

 

 

 

GetBean 的大概过程:

1. 先试着从单例缓存对象里获取。

2.从父容器里取定义,有则由父容器创建。

3. 如果是单例,则走单例对象的创建过程:在 spring 容器里单例对象和非单例对象的创建过程是一样的。都会调用父 类 AbstractAutowireCapableBeanFactory 的 createBean 方法。 不同的是单例对象只创建一次并且需要缓 存起来。 DefaultListableBeanFactory 的父类 DefaultSingletonBeanRegistry 提供了对单例对 象缓存等支持工作。所以是单例对象的话会调用 DefaultSingletonBeanRegistry 的 getSingleton 方法,它会间 接调用AbstractAutowireCapableBeanFactory 的 createBean 方法。

如果是 Prototype 多例则直接调用父类 AbstractAutowireCapableBeanFactory 的 createBean 方法。

Bean的作用域

Scope

Prototype:原型模式,容器初始化的时候并不会创建bean对象,而在getBean的时候创建, 如果多次getBean,则会创建多个bean对象。

Singleton:单例模式,

lazy-init为false(默认是false,所以可以不用设置),则 ApplicationContext启动的时候就实例化该Bean,并且将实例化的Bean放在一个map结构的缓存中,下次再使用该Bean的时候, 直接从这个缓存中取

lazy-init为true,则该Bean的实例化是在第一次使用该Bean的时候进行实例化

request:对于每次 HTTP 请求,都将会产生一个不同的 Bean 实例。

session:对于每个不同的 HTTP session,都将产生一个不同的 Bean

Bean的装配过程

①默认装配方式:调用无参构造器的方式由spring容器创建的

②动态工厂Bean:由工厂创建出来的

③静态工厂Bean:由静态工厂创建出来的

下面的案例就讲讲动态工厂bean和静态工厂bean的两种方式。虽然这两种很少用到,但万一哪一天碰到了呢

第一种:动态工厂bean

定义接口:

public interface ISomeService {
	String doFirst();
	void duSecond();

}

实现类:

public class SomeServiceImpl implements ISomeService {

	
	public SomeServiceImpl() {
		System.out.println("对象创建了。。。。。");
	}

	@Override
	public String doFirst() {
		System.out.println("执行doFirst方法");
		return "abcd";
	}

	@Override
	public void duSecond() {
		System.out.println("执行读second方法");

	}

}

工厂类:

/**
 * 动态工厂
 * @author Administrator
 *
 */
public class ServiceFactory {
	public ISomeService getSomeService(){
		return new SomeServiceImpl();
	}

}

测试类:

public class MyTest {
	@Test
	public void test01() {
		String resource="com/liuz/ba02/applicationContext.xml";
		ApplicationContext ac = new ClassPathXmlApplicationContext(resource);
		ISomeService service=(ISomeService)ac.getBean("someService");
		service.doFirst();
		service.duSecond();

	}
}

applicationContext.xml

<?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">
       <bean id="serviceFactory" class="com.liuz.ba02.ServiceFactory"></bean>
       <!-- someService是由serviceFactory这个工厂bean的getSomeService方法创建的 -->
       <bean id="someService" factory-bean="serviceFactory" factory-method="getSomeService"></bean>
		
</beans>

运行效果:

在这个例子中对象就是通过动态工厂ServiceFactory类创建的。

第二种 静态工厂bean

接口:

public interface ISomeService {
	String doFirst();
	void duSecond();

}

实现类:

public class SomeServiceImpl implements ISomeService {

	
	public SomeServiceImpl() {
		System.out.println("对象创建了。。。。。");
	}

	@Override
	public String doFirst() {
		System.out.println("执行doFirst方法");
		return "abcd";
	}

	@Override
	public void duSecond() {
		System.out.println("执行读second方法");

	}

}

工厂类:

/**
 * 静态工厂
 * @author Administrator
 *
 */
public class ServiceFactory {
	Public static ISomeService getSomeService(){
		Return new SomeServiceImpl();
	}

}

测试类:

public class MyTest {
	@Test
	public void test01() {
		String resource="com/liuz/ba02/applicationContext.xml";
		ApplicationContext ac = new ClassPathXmlApplicationContext(resource);
		ISomeService service=(ISomeService)ac.getBean("someService");
		service.doFirst();
		service.duSecond();

	}
}

applicationContext.xml

<?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">
    
      <!-- someService对象是由serviceFactory这个类的getSomeService方法创建的 -->
      <bean id="someService" class="com.liuz.ba03.ServiceFactory" factory-method="getSomeService"></bean>
		
</beans>

这2中创建bean的方式就到这里就结束了。

Bean后处理器

在目标 Bean 初始化完毕之前与之后执行。它们的返回值为:功能被扩展或增强后的 Bean 对象。(这个功能在项目中用得比较少),在这里就不做介绍了,具体看文档。

定制Bean的生命始末

可以为 Bean 定制初始化后的生命行为,也可以为 Bean 定制销毁前的生命行为。也即是说在初始化完毕之后,销毁之前,执行自己定义的方法。

实现的方式分三个步骤

第一步:在你的bean类里面定义初始化之后和销毁之前的两个方法,例如

第二步:在配置文件的<bean/>标签中增加如下属性:
init-method:指定初始化方法的方法名
destroy-method:指定销毁方法的方法名

注意,若要看到 Bean 的 destroy-method 的执行结果,需要满足两个条件:
(1)Bean 为 singleton,即单例,spring默认的获取bean的方式就是单例的。
(2)要确保容器关闭。接口 ApplicationContext 没有 close()方法,但其实现类有。所以,要在调用bean对象的地方
将 ApplicationContext 强转为其实现类对象,或直接创建的就是实现类对象。

 

Bean的生命周期

这个知识点,可以说是一个重点,虽然说bean的生命周期一共有11个步骤,不能记得很清楚,但大概的印象还是要有的。

第一步:调用无参构造方法

  第二步:调用所有属性的set方法

  第三步:如果类实现了BeanNameAware 则可以获取到bean的id 执行setBeanName()

  第四步:如果类实现了BeanFactoryAware,则可以获取到beanFactory对象 执行setBeanFactory()

  第五步:如果类实现了BeanFactoryAware 则执行bean后处理器的before方法 postProcessBeforeInitialization()

  第六步:如果类实现了InitializingBean接口,则执行afterPropertiesSet()这个方法,这个方法属于一个标志性的方法--属性设置结束了,标志着bean初始化完毕了

 第七步:如果xml的bean配置了init-method,则执行初始化之后的方法

 第八步:如果类实现了BeanFactoryAware 则执行bean后处理器的after方法 postProcessAfterInitialization()

 第九步:执行自己的业务方法 add update delete select

  第十步:如果类实现了DisposableBean接口,并且的调用的地方写了((ClassPathXmlApplicationContext)ac).close();则执行destroy()方法 准备销毁

 第十一步:如果xml的bean里面配置了destroy-method则调用这里的方法销毁

为了说明这11个步骤,下面写了一个测试案例:

新建一个java project  jar包我就不说了,跟上面的一样

定义接口:

public interface ISomeService {
	String doFirst();
	void duSecond();

}

实现类:

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

public class SomeServiceImpl implements ISomeService,BeanNameAware,BeanFactoryAware,InitializingBean,DisposableBean {
	private String userDao;
	private String deptDao;
	
	
	
	
	public void setUserDao(String userDao) {
		System.out.println("step2:执行setUserDao");
		this.userDao = userDao;
	}

	public void setDeptDao(String deptDao) {
		System.out.println("step2:执行setDeptDao");
		this.deptDao = deptDao;
	}

	public SomeServiceImpl() {
		System.out.println("step1:对象创建了。。。。。");
	}

	@Override
	public String doFirst() {
		System.out.println("step9:执行主业务方法");
		return "abcd";
	}

	@Override
	public void duSecond() {
		System.out.println("执行读second方法");

	}

	@Override
	public void setBeanName(String name) {
		System.out.println("step3:beanName="+name);
		
	}

	@Override
	public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
		System.out.println("step4:获取到beanFactory="+beanFactory);
		
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		System.out.println("step6:属于一个标志性的方法--属性设置结束了,标志着bean初始化完毕了");
		
	}
	public void initAfter(){
		System.out.println("step7:初始化之后");
	}

	@Override
	public void destroy() throws Exception {
		System.out.println("step10:准备开始执行销毁");
		
	}
	public void preDestory(){
		System.out.println("step11:执行销毁");
	}


}

Bean后处理器

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

public class MyBeanPostProcess implements BeanPostProcessor {
	/**
	 * bean:当前调用执行bean后处理器的bean对象
	 * beanName:当前调用执行bean后处理器的bean对象的id
	 */
	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName)
			throws BeansException {
		System.out.println("step5:执行bean后处理器before");
		return bean;
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName)
			throws BeansException {
		System.out.println("step8:执行bean后处理器after");
		return bean;
	}

}

测试类:

public class MyTest {
	@Test
	public void test01() {
		String resource="com/liuz/ba07/applicationContext.xml";
		ApplicationContext ac = new ClassPathXmlApplicationContext(resource);
	ISomeService service=(ISomeService)ac.getBean("SomeService");
		service.doFirst();
		((ClassPathXmlApplicationContext)ac).close();
		//service.duSecond();

	}
}

applicationContext.xml

<?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">
       
		  <bean id="SomeService" class="com.liuz.ba07.SomeServiceImpl" init-method="initAfter" destroy-method="preDestory">
		  <property name="userDao" value="user1"></property>
		  <property name="deptDao" value="dept1"></property>
		  </bean>
		  <bean class="com.liuz.ba07.MyBeanPostProcess"></bean>
</beans>

运行效果:

bean的生命周期到这里就结束了。

下面就是关于DI的内容了。

基于XML的DI

在这里要解释一下DI,很多人都知道DI是注入,但到底注入什么?把什么注入到什么?为什么一说道IoC大家第一反应想到的事DI

第一:DI是IoC目前最好的一种方式,还有一种方式叫DL(依赖查找)

第二:所谓的注入是将属性值注入到bean对象身上,前面所有的bean对象的获取,都是为了这一步,给bean对象赋值。当然了对于service dao这种bean也许没有属性,自然用不到注入什么属性值,但对于自己定义的bean对象,类似于model,是一定要用到注入的。

第一种:设值注入

设值注入就是靠在xml中给对象设置值,在做POI导出的时候就用到了。

还是java project

定义Student和School类:

public class Student {
	private String name;
	private Integer age;
	private School school;
	public void setName(String name) {
		this.name = name;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
	public void setSchool(School school) {
		this.school = school;
	}
	@Override
	public String toString() {
		return "Student [name=" + name + ", age=" + age + ", school=" + school
				+ "]";
	}
}
public class School {
	private String sname;
	public void setSname(String sname) {
		this.sname = sname;
	}
	@Override
	public String toString() {
		return "School [sname=" + sname + "]";
	}
}

applicationContext.xml

​
<?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">
	<!-- 注册service对象 等同于ISomeService service = new SomeServiceImpl(); 这个对象是再spring容器被初始化时候创建的。 -->
	<bean id="mySchool" class="com.liuz.di02.School">
	<property name="sname" value="清华大学"></property>
	</bean>
	<bean id="myStudent" class="com.liuz.di02.Student">
	<!-- 第一种 -->
		<!-- <constructor-arg index="0" value="张三"/>
		<constructor-arg index="1" value="23"/>
		<constructor-arg index="2" ref="mySchool"/> -->
		<!-- 第二种 -->
		<!-- <constructor-arg name="name" value="李四"/>
		<constructor-arg name="age" value="24"/>
		<constructor-arg name="school" ref="mySchool"/> -->
		<!-- 第三种 -->
		<constructor-arg value="王五"/>
		<constructor-arg value="25"/>
		<constructor-arg ref="mySchool"/>
		
	</bean>
</beans>

​

测试类:

public class MyTest {
	@Test
	public void test01() {
	String resource="com/liuz/di01/applicationContext.xml";
	ApplicationContext ac = new ClassPathXmlApplicationContext(resource);
	Student student=(Student)ac.getBean("myStudent");
	System.out.println(student);

	}
}

运行结果:

第二种:构造注入

构造注入不需要无参构造器就可以了。但一定要有全部属性的带参构造器,因为这种方式调用的就是带参的构造器。

案例就不列举了。具体的实现请下载下面的源码。

第三种:p命名空间设置注入

底层调用的set方法,所有对象的属性一定要有set方法。

注意:在applicationContext.xml中一定要加上约束

xmlns:p="http://www.springframework.org/schema/p",具体实现看下载下来的代码

第四种: c命名空间构造注入

底层用的是构造方法,所以一定要把构造方法写出来。

第五种:集合属性注入 具体看源码(很简单)

第六种:byName方式域属性自动注入 

byName自动注入,是将域属性名作为id到容器中查找相同名称的bean自动注入

第七种: byType方式域属性自动注入

根据域属性的类型到容器中查找具有 is a关系的bean自动注入。

要求:相同类型的bean不能多余1个

基于注解的DI

主要使用到的3个注解

@Component("mySchool")表明它是一个组件,后面括号里面给组件起个名 相当于xml配置方式注册bean的id

@Value("清华大学") 注入值

域属性的注入:域属性的复制有2种方式 byType 和byName

@Autowired就是属于byType

项目案例:

新建maven项目:

引入这些依赖包

<dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>4.2.1.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-beans</artifactId>
      <version>4.2.1.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.9</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>4.2.1.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.2.1.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-expression</artifactId>
      <version>4.2.1.RELEASE</version>
    </dependency>
   <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>com.springsource.org.apache.commons.logging</artifactId>
      <version>1.1.1</version>
    </dependency>
    <dependency>
      <groupId>org.apache.log4j</groupId>
      <artifactId>com.springsource.org.apache.log4j</artifactId>
      <version>1.2.15</version>
    </dependency>
  </dependencies>

项目结构图

School.java

@Component("mySchool")
public class School {
	@Value("清华大学")
	private String sname;
	public void setSname(String sname) {
		this.sname = sname;
	}
	@Override
	public String toString() {
		return "School [sname=" + sname + "]";
	}
}

Student.java
@Component("myStudent")
public class Student {
	@Value("张三")
	private String name;
	@Value("23")
	private Integer age;
	@Autowired
	private School school;
	public void setName(String name) {
		this.name = name;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
	public void setSchool(School school) {
		this.school = school;
	}
	@Override
	public String toString() {
		return "Student [name=" + name + ", age=" + age + ", school=" + school
				+ "]";
	}
}

applicationContext.xml

<?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"> <!-- bean definitions here -->
<!-- 只要是给的是XXpackage 写的都是. 如果看到的是location、locations就是用/ -->
<context:component-scan base-package="com.liuz.di01"/>
</beans>

测试类:

public class MyTest {
	@Test
	public void test01() {
	String resource="com/liuz/di01/applicationContext.xml";
	ApplicationContext ac = new ClassPathXmlApplicationContext(resource);
	Student student=(Student)ac.getBean("myStudent");
	System.out.println(student);

	}
}

注入成功!

总结一下实现注解注入的步骤:

①在实体类上加上@Component 后面跟上括号,并在括号里面写上bean的id

②在每个属性上加上@Value("清华大学")后面括号里面放value

   如果是域属性对象,则可以使用byType方式和byName注入

@Autowired:就是byType方式

③在spring的配置文件加入扫包的配置

<context:component-scan base-package="com.liuz.di01"/>

 base-package="com.liuz.di01"会扫描自己以及其子包

 base-package="com.liuz.di01.*"扫描所有的子包

在这里补充说明一下byType方式和byName方式注入

@autowire是 byType的方式,就等同于xml的byType注入方式,在applicationContext.xml的bean后面配置的autowire=”byType”,会根据域属性类型到容器中查找is  a 关系的bean自动注入。使用byType的方式的要求是相同的类型的bean只能有一个。

@Qualifier("mySchool") 是byName的方式,是要求你要注入的域属性的bean的id要和域属性名相同,spring会根据域属性名去找域属性对象的bean。使用byName方式的时候是

@autowire+@Qualifier("mySchool") 连着一起用

@Component 具有相同功能不同意义的注解还有3个

@Repository:注解在dao实现类上

@Service:注解在service上

@Controller 注解在controller

总结spring里面涉及到的注解以及功能解释

功能:定义组件

@Component:定义组件

@Repository:注解在dao实现类上

@Service:注解在service上

@Controller 注解在controller

实现域属性注入

  • byType

第一种:@autowire 根据is a关系自动注入

第二种:@Resource 要求jre1.6以及以上

  • byName

第一种:@Autowired

@Qualifier("mySchool")

两个一起用

第二种:@Resource(name="mySchool") 括号里面放域属性bean的id

实现定义bean生命始末

@PostConstruct 声明初始化完毕后的方法

@PreDestroy  声明销毁前的方法。

注意:执行这2个方法的前提是手动关闭容器

((ClassPathXmlApplicationContext)ac).close();

在调用bean的地方加上这一行代码。

@Resource 自动的根据byType的方式来注入,如果后面跟着value,就使用byName的方式。

@Configuration 声明这个类将作为spring容器来使用了。

 

@javaConfig定义一个java类,这个类将来就是容器

使用Spring的Junit测试

基于注解和xml方法共同使用

配置文件的优先级高于注解的优先级

好处:当项目里面用到了注解,并且bean的属性给了set器,如果要改以前设置的值,则改xml就可以了。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sonwing_for

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值