zoukankan      html  css  js  c++  java
  • Spring详解篇之IoC控制反转

    ###一.Spring概况

    • spring是一个开源框架
    • 是一个轻量的控制反转和面向切面的容器框架
    • 大小和开销都是轻量的。
    • 通过控制反转技术可以达到松耦合的目的
    • 切面编程,允许通过分离应用的业务逻辑。
    • 包含并管理应用对象的配置和生命周期,是一个容器,并且能够组装。

    二、IoC

    ioc控制反转:控制权转移,应用程序本身不负责依赖对象的创建和维护,而是由外部容器负责和维护。ioc的目的是创建对象并且组装对象之间的关系。

    ####1.bean容器初始化

    • –org.springframework.beans

    • –org.springframework.context

    • beanfactory 提供配置结构和基本功能,加载并初始化bean

    • applicationContext 保存bean对象并在应用中被应用

    2.spring注入:

    • spring 注入是指在启动 spring容器加载bean配置的时候,完成对变量的赋值行为。
    • 常见的注入方式:设值注入、构建注入

    举个例子,构建注入

    dao层

    public interface InjectionDAO {
    	
    	public void save(String arg);
    	
    }
    
    
    
    public class InjectionDAOImpl implements InjectionDAO {
    	
    	public void save(String arg) {
    		//模拟数据库保存操作
    		System.out.println("保存数据:" + arg);
    	}
    
    }
    
    

    service 层接口:

    public interface InjectionService {
    	
    	public void save(String arg);
    	
    }
    
    
    

    service 层实现:

    public class InjectionServiceImpl implements InjectionService {
    	
    	private InjectionDAO injectionDAO;
    	
    	//构造器注入
    	public InjectionServiceImpl(InjectionDAO injectionDAO1) {
    		this.injectionDAO = injectionDAO1;
    	}
    	
    	//设值注入
    	public void setInjectionDAO(InjectionDAO injectionDAO) {
    		this.injectionDAO = injectionDAO;
    	}
    
    	public void save(String arg) {
    		//模拟业务操作
    		System.out.println("Service接收参数:" + arg);
    		arg = arg + ":" + this.hashCode();
    		injectionDAO.save(arg);
    	}
    
    

    在spring 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="injectionService" class="com.forezp.ioc.injection.service.InjectionServiceImpl">
            	<constructor-arg name="injectionDAO1" ref="injectionDAO"></constructor-arg>
            </bean>
    
            <bean id="injectionDAO" class="com.forezp.ioc.injection.dao.InjectionDAOImpl"></bean>
    
     </beans>
    
    
    

    单元测试

    本系列文章单元测试基类

    
    public class UnitTestBase {
    	
    	private ClassPathXmlApplicationContext context;
    	
    	private String springXmlpath;
    	
    	public UnitTestBase() {}
    	
    	public UnitTestBase(String springXmlpath) {
    		this.springXmlpath = springXmlpath;
    	}
    	
    	@Before
    	public void before() {
    		if (StringUtils.isEmpty(springXmlpath)) {
    			springXmlpath = "classpath*:spring-*.xml";
    		}
    		try {
    			context = new ClassPathXmlApplicationContext(springXmlpath.split("[,\s]+"));
    			context.start();
    		} catch (BeansException e) {
    			e.printStackTrace();
    		}
    	}
    	
    	@After
    	public void after() {
    		context.destroy();
    	}
    	
    	@SuppressWarnings("unchecked")
    	protected <T extends Object> T getBean(String beanId) {
    		try {
    			return (T)context.getBean(beanId);
    		} catch (BeansException e) {
    			e.printStackTrace();
    			return null;
    		}
    	}
    	
    	protected <T extends Object> T getBean(Class<T> clazz) {
    		try {
    			return context.getBean(clazz);
    		} catch (BeansException e) {
    			e.printStackTrace();
    			return null;
    		}
    	}
    
    }
    
    

    单元测试:

    
    @RunWith(BlockJUnit4ClassRunner.class)
    public class TestInjection extends UnitTestBase {
    	
    	public TestInjection() {
    		super("classpath:spring-injection.xml");
    	}
    	
    	@Test
    	public void testSetter() {
    		InjectionService service = super.getBean("injectionService");
    		service.save("这是要保存的数据");
    	}
    	
    	@Test
    	public void testCons() {
    		InjectionService service = super.getBean("injectionService");
    		service.save("这是要保存的数据");
    	}
    	
    }
    
    
    

    运行打印:

    Service接收参数:这是要保存的数据

    保存数据:这是要保存的数据:1247298779

    这个例子说明,我们可以通过ClassPathXmlApplicationContext.getBean()获取到了service,这个service 是通过xml配置注入到容器中,并且注入的时候通过构造函数的设置了成员变量dao。

    三.bean的配置项

    ####3.1 bean常见的配置项,如下:

    • Id
    • Class
    • Scope
    • Constructor arguments
    • Properties
    • Autowiring mode
    • lazy-initialization mode
    • Initialization/destruction method

    3.2 bean的作用域

    • singleton: 单列
    • prototype每次使用都会创建新实例
    • request :每次http请求创建一个实例,仅在当前 request有效
    • session : 当前session有效

    举个例子:
    测试sinleton和prototype

    创建bean实例

    public class BeanScope {
    	
    	public void say() {
    		System.out.println("BeanScope say : " + this.hashCode());
    	}
    	
    }
    
    

    在xml中配置,作用域为singleton

    <?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="beanScope" class="com.imooc.bean.BeanScope" scope="singleton"></bean>
            
     </beans>
    
    
    

    单元测试:

    @RunWith(BlockJUnit4ClassRunner.class)
    public class TestBeanScope extends UnitTestBase {
    	
    	public TestBeanScope() {
    		super("classpath*:spring-beanscope.xml");
    	}
    	
    	@Test
    	public void testSay() {
    		BeanScope beanScope = super.getBean("beanScope");
    		beanScope.say();
    		
    		BeanScope beanScope2 = super.getBean("beanScope");
    		beanScope2.say();
    	}
    	
    
    }
    
    
    

    运行单元测试:

    BeanScope say : 1113008012

    BeanScope say : 1113008012

    在xml中配置,作用域为prototype

    <?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="beanScope" class="com.imooc.bean.BeanScope" scope="prototype"></bean>
            
     </beans>
    
    
    

    运行单元测试

    BeanScope say : 144724468

    BeanScope say : 1432645272

    由此可发现sington在bean容器是一个实例,而prototype创建了二个实例。

    四.bean的生命周期

    包括以下几个方面:

    • 定义,在xml中配置
    • 初始化
    • 使用
    • 销毁

    初始化

    有两种方式

    • 实现 InitializingBeean接口,覆盖afterPropertiesSet()
    • 配置init-method方法

    销毁

    也有两种方式:

    • 实现DisposableBean接口,覆盖destroy();
    • 配置 destroy-method

    举个例子:

    创建bean实例:

    public class BeanLifeCycle implements InitializingBean, DisposableBean {
    	
    	public void defautInit() {
    		System.out.println("Bean defautInit.");
    	}
    	
    	public void defaultDestroy() {
    		System.out.println("Bean defaultDestroy.");
    	}
    
    	@Override
    	public void destroy() throws Exception {
    		System.out.println("Bean destroy.");
    	}
    
    	@Override
    	public void afterPropertiesSet() throws Exception {
    		System.out.println("Bean afterPropertiesSet.");
    	}
    	
    	public void start() {
    		System.out.println("Bean start .");
    	}
    	
    	public void stop() {
    		System.out.println("Bean stop.");
    	}
    	
    }
    
    

    bean的配置:

    <?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" 
            default-init-method="defautInit" default-destroy-method="defaultDestroy">
            
            <bean id="beanLifeCycle" class="com.imooc.lifecycle.BeanLifeCycle"  init-method="start" destroy-method="stop"></bean>
    	
     </beans>
    
    
    

    单元测试:

    @RunWith(BlockJUnit4ClassRunner.class)
    public class TestBeanLifecycle extends UnitTestBase {
    	
    	public TestBeanLifecycle() {
    		super("classpath:spring-lifecycle.xml");
    	}
    	
    	@Test
    	public void test1() {
    		super.getBean("beanLifeCycle");
    	}
    	
    }
    
    
    

    运行:

    Bean afterPropertiesSet.

    Bean start .

    Bean destroy.

    Bean stop.

    同时实现两种方式的初始化方法的执行顺序: 接口实现优先于xml中的配置。

    五.bean的自动装配(Autowiring)

    • No: 不做任何操作
    • byname:根据属性名自动装配
    • byType:如果容器存在一个与指定类型相同的bean,则自动装配,如果存在多个,则抛出异常。
    • constructor:与 byType类似,不同之处它在于构造器的参数。

    举例子:
    1.byName方式:

    创建一个dao:

    public class AutoWiringDAO {
    	
    	public void say(String word) {
    		System.out.println("AutoWiringDAO : " + word);
    	}
    
    }
    
    
    

    创建一个service

    public class AutoWiringService {
    	
    	private AutoWiringDAO autoWiringDAO;
    
    
    	public void setAutoWiringDAO(AutoWiringDAO autoWiringDAO) {
    		System.out.println("setAutoWiringDAO");
    		this.autoWiringDAO = autoWiringDAO;
    	}
    	
    	public void say(String word) {
    		this.autoWiringDAO.say(word);
    	}
    
    }
    
    

    在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" 
            default-autowire="byName">
            
            <bean id="autoWiringService" class="com.imooc.autowiring.AutoWiringService" ></bean>
            
            <bean id="autoWiringDAO" class="com.imooc.autowiring.AutoWiringDAO" ></bean>
    	
     </beans>
    
    

    单元测试:

    @RunWith(BlockJUnit4ClassRunner.class)
    public class TestAutoWiring extends UnitTestBase {
    	
    	public TestAutoWiring() {
    		super("classpath:spring-autowiring.xml");
    	}
    	
    	@Test
    	public void testSay() {
    		AutoWiringService service = super.getBean("autoWiringService");
    		service.say(" this is a test");
    	}
    
    }
    
    

    运行:

    setAutoWiringDAO

    AutoWiringDAO : this is a test

    通过default-autowire=“byName”;
    AutoWiringService 自动获取了autoWiringDAO的实例。

    2.byTYpe

    将在xml中配置改为byType :

    <?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" 
            default-autowire="byName">
            
            <bean id="autoWiringService" class="com.imooc.autowiring.AutoWiringService" ></bean>
            
            <bean id="autoWiringDAO" class="com.imooc.autowiring.AutoWiringDAO" ></bean>
    	
     </beans>
    
    

    其他不变,运行和byName 一样。

    3.constructor

    <?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" 
            default-autowire="constructor">
            
            <bean id="autoWiringService" class="com.imooc.autowiring.AutoWiringService" ></bean>
            
            <bean id="autoWiringDAO" class="com.imooc.autowiring.AutoWiringDAO" ></bean>
    	
     </beans>
    
    

    AutoWiringService 中增加构造器

    
    public class AutoWiringService {
    	
    	private AutoWiringDAO autoWiringDAO;
    	
    	public AutoWiringService(AutoWiringDAO autoWiringDAO) {
    		System.out.println("AutoWiringService");
    		this.autoWiringDAO = autoWiringDAO;
    	}
    
    	public void setAutoWiringDAO(AutoWiringDAO autoWiringDAO) {
    		System.out.println("setAutoWiringDAO");
    		this.autoWiringDAO = autoWiringDAO;
    	}
    	
    	public void say(String word) {
    		this.autoWiringDAO.say(word);
    	}
    
    }
    
    
    

    允行:

    AutoWiringDAO : this is a test

    六.classPath扫描与组件管理

    从spring 3.0开始,spring javaConfig 项目提供了许多特性,包括使用java而不是xml

    1.比如注解

    @Configuration
    @Bean
    @Import
    @DependsOn

    @Component 是一个通用注解,应用于任何bean

    @Reposity注解DAO

    @Service注解service

    @Controller注解controller

    2.spring可以自动检测类并注册bean到applicationContext中。比如
    @Service @Reposity等

    3.< context:annoation-config />会查找applicationContext中bean的注解。

    扫描 :< context:component-scan> 包含< context:annoation-config/>,通常只需要使用前者。

    <context:component-scan base-package="com.forezp" > 
    

    举个例子:
    通过扫描获取bean,在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" >
            
            <context:component-scan base-package="com.forezp.beanannotation"></context:component-scan>
            
     </beans>
    
    

    定义一个bean类:
    其中scope 注解表示bean的作用域,默认singleton。Component默认类名并将第一个字母小写。

    @Scope
    @Component
    public class BeanAnnotation {
    	
    	public void say(String arg) {
    		System.out.println("BeanAnnotation : " + arg);
    	}
    	
    	public void myHashCode() {
    		System.out.println("BeanAnnotation : " + this.hashCode());
    	}
    	
    }
    
    

    单元测试:

    @RunWith(BlockJUnit4ClassRunner.class)
    public class TestBeanAnnotation extends UnitTestBase {
    	
    	public TestBeanAnnotation() {
    		super("classpath*:spring-beanannotation.xml");
    	}
    	
    	@Test
    	public void testSay() {
    		BeanAnnotation bean = super.getBean("beanAnnotation");
    		bean.say("This is test.");
    		
    		//bean = super.getBean("bean");
    		//bean.say("This is test.");
    	}
    
    }
    

    运行:

    BeanAnnotation : This is test.

    七、Autowired

    • @Autowired可以用于setter方法上
    • 可以用于成员变量
    • 可以用于构造器

    举个例子:

    采用包扫描:

    <?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" >
            
            <context:component-scan base-package="com.forezp.beanannotation"></context:component-scan>
            
     </beans>
    
    
    

    采用注解:DAO层

    @Repository
    public class InjectionDAOImpl implements InjectionDAO {
    	
    	public void save(String arg) {
    		//模拟数据库保存操作
    		System.out.println("保存数据:" + arg);
    	}
    
    }
    
    
    

    service层:

    @Service
    public class InjectionServiceImpl implements InjectionService {
    	
    //	@Autowired
    	private InjectionDAO injectionDAO;
    	
    	@Autowired
    	public InjectionServiceImpl(InjectionDAO injectionDAO) {
    		this.injectionDAO = injectionDAO;
    	}
    	
    //	@Autowired
    	public void setInjectionDAO(InjectionDAO injectionDAO) {
    		this.injectionDAO = injectionDAO;
    	}
    
    
    
    	public void save(String arg) {
    		//模拟业务操作
    		System.out.println("Service接收参数:" + arg);
    		arg = arg + ":" + this.hashCode();
    		injectionDAO.save(arg);
    	}
    	
    }
    
    

    单元测试:

    @RunWith(BlockJUnit4ClassRunner.class)
    public class TestInjection extends UnitTestBase {
       
       public TestInjection() {
       	super("classpath:spring-beanannotation.xml");
       }
       
       @Test
       public void testAutowired() {
       	InjectionService service = super.getBean("injectionServiceImpl");
       	service.save("This is autowired.");
       }
    }
    
    

    运行:

    Service接收参数:This is autowired.

    保存数据:This is autowired.:1641742937

    八、基于java的容器注解@Bean

    • @Bean 标识一个用于配置和初始化一个由springIoC容器管理的新对象的方法,类似于 xml配置文件的</ bean>

    举个例子:
    用注解去代替xml文件

    @Configuration
    
    public class StoreConfig {
    	
    
    @Bean(name = "stringStore", initMethod="init", destroyMethod="destroy")
    	public Store stringStore() {
    		return new StringStore();
    	}
    	
    

    javabean StringStore类

    
    public class StringStore implements Store<String> {
    	
    	public void init() {
    		System.out.println("This is init.");
    	}
    	
    	public void destroy() {
    		System.out.println("This is destroy.");
    	}
    	
    }
    
    

    单元测试:

    @RunWith(BlockJUnit4ClassRunner.class)
    public class TestJavabased extends UnitTestBase {
    	
    	public TestJavabased() {
    		super("classpath*:spring-beanannotation.xml");
    	}
    	
    	@Test
    	public void test() {
    		Store store = super.getBean("stringStore");
    		System.out.println(store.getClass().getName());
    	}
    	
    	}
    
    

    另外可以用ImportResource注解类获取资源文件信息:

    @Configuration
    @ImportResource("classpath:config.xml")
    public class StoreConfig {
    	
    	
    	@Value("${url}")
    	private String url;
    	
    	@Value("${jdbc.username}")
    	private String username;
    	
    	@Value("${password}")
    	private String password;
    	
    

    九、JSR-250

    • spring支持jsr-250
    • @Resource注解变量或者setter 方法
    • Resource注解有一个name属性,默认该值作为被注入bean的名称。

    举个例子:

    Dao层:

    @Repository
    public class JsrDAO {
    	
    	public void save() {
    		System.out.println("JsrDAO invoked.");
    	}
    	
    }
    
    
    

    service层:

    
    
    @Service
    public class JsrServie {
    	
    	@Resource
    	private JsrDAO jsrDAO;
    	
    //	@Resource
    //	public void setJsrDAO(@Named("jsrDAO") JsrDAO jsrDAO) {
    	//	this.jsrDAO = jsrDAO;
    	//}
    	
    	@PostConstruct
    	public void init() {
    		System.out.println("JsrServie init.");
    	}
    	
    	@PreDestroy
    	public void destroy() {
    		System.out.println("JsrServie destroy.");
    	}
    
    	public void save() {
    		jsrDAO.save();
    	}
    	
    }
    
    


    扫码关注公众号有惊喜

    (转载本站文章请注明作者和出处 方志朋的博客

  • 相关阅读:
    20162317袁逸灏 第十六周实验报告:实验五 网络编程与安全
    20162317-20162315结对编程-四则运算(挑战出题)
    第十四周实验报告:实验四 Android程序设计
    20162305 2016-2017-2 《程序设计与数据结构》第9周学习总结
    20162305 2016-2017-2 《程序设计与数据结构》第8周学习总结
    20162305 实验二 Java面向对象程序设计 实验报告
    20162305 2016-2017-2 《程序设计与数据结构》第7周学习总结
    20162305 2016-2017-2 《程序设计与数据结构》第6周学习总结
    20162305 2016-2017-2 《程序设计与数据结构》第5周学习总结
    20162305 李昱兴 实验报告一
  • 原文地址:https://www.cnblogs.com/forezp/p/9852176.html
Copyright © 2011-2022 走看看