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

Spring学习笔记-IoC

2017-11-26 22:31 393 查看

Spring概述

Spring框架是轻量级的Java EE框架,不提供某种功能,只是将所有组件部署到Spring中管理、维护、执行,就像粘合剂。
Spring使用简单的POJO(Plain Old Java Object)来进行企业级开发,每个被Spring管理的Java对象都是一个Bean,Spring提供了一个IoC容器用来初始化对象。

Spring框架组成

7大模块
Core模块:核心类库,主要实现IoC(Inversion of Control)功能。
AOP模块:提供AOP(Aspect Oriented Programming)机制。
ORM模块:对常用ORM(Object Relational Mapping)框架管理、支持,如Hibernate。
DAO模块:Data Access Object,提供对JDBC等支持和封装
Web模块:提供对Struts等web框架支持。
Context模块:提供框架式Bean访问方式,其他程序可通过Context访问Spring的Bean资源。
Web MVC模块:轻量级MVC实现。
 

Core模块

Core模块主要实现反向控制(IoC)与依赖注入DI(Dependency Injection)、Bean配置以及加载。
Spring中最核心的两个类:
DefaultListableBeanFactory,是Spring注册及加载bean的默认实现
XmlBeanDefinitionReader,资源文件读取,解析及注册。
 
Beans为Spring里各种对象,一般要配置在Spring配置文件中
BeanFactory为创建Beans的Factory,Spring通过BeanFactory加载各种Beans
BeanDefinition为Bean在配置文件中的定义,id与class
ApplicationContext为配置文件
加载方式有三种:本地文件、Classpath、Web应用中依赖servlet或ListenerFileSystemXmlApplicationContext context=
        new FileSystemXmlApplicationContext("D:\\appcontext.xml");

ClassPathXmlApplicationContextcontext1=
        new ClassPathXmlApplicationContext("classpath:spring-context.xml");<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet> 

IOC

控制反转,控制权的转移,应用程序本身不负责依赖对象的创建和维护,而是由外部容器来做。
DI(依赖注入)是其一种实现方式,Spring中IOC和DI是同等概念。容器负责创建对象和维护对象间的依赖关系,而不是对象本身。
目的:解耦,体现组合概念。
 

BeanFactory

BeanFactory是实例化、配置、管理众多Bean的容器。BeanFactory根据配置实例化Bean对象,并设置相互的依赖。
BeanFactory可用接口org.springframework.beans.factory.BeanFactory表示,最常用的实现为org.springframework.beans.factory.xml.XmlBeanFactory(过时,现在使用ApplicationContext),可用加载xml配置文件。
Web程序中用户不需要实例化BeanFactory,Web加载时会自动实例化。
Java桌面程序,需要实例化BeanFactory,从BeanFactory中获取Bean,构造函数的参数为配置文件的路径。如:BeanFactory bf = new XmlBeanFactory(
        new ClassPathResource("applicationContext.xml"));
Student student = (Student)bf.getBean("studentBean");
student.say(); 

ApplicationContext

ApplicationContext拥有BeanFactory的全部功能,在绝大多数的"典型的"企业应用和系统,ApplicationContext都优先于BeanFactory。
XmlBeanFactory已经废弃,目前用ApplicationContext获得Bean对象。
ApplicationContext的三个实现类:
1、ClassPathXmlApplication:从classpath下加载配置文件(适合于相对路径方式加载),classpath: 前缀是不需要的,默认就是指项目的classpath路径下面。ApplicationContext factory = new ClassPathXmlApplicationContext(
        "applicationContext.xml");
Student student1 = (Student) factory.getBean("studentBean");
student1.say();2、FileSystemXmlApplication:从文件绝对路径加载配置文件,如果从classpath中读取需要加classpathApplicationContext context = new FileSystemXmlApplicationContext(
        "classpath:applicationContext.xml");
Student student = (Student) context.getBean("studentBean");
student.say();3、XmlWebApplicationContext:专为web工程定制的方法,推荐Web项目中使用。例如:
ServletContext servletContext =request.getSession().getServletContext();
ApplicationContext ctx =WebApplicationContextUtils.getWebApplicationContext(servletContext);

两者区别

相同点
上述两者都是通过加载XMl配置文件的方式加载Bean,而后者是前者的扩展,提供了更多的功能,即ApplicationContext拥有BeanFactory的全部功能,在绝大多数的"典型的"企业应用和系统,ApplicationContext都优先于BeanFactory。
不同点
BeanFactory是延迟加载,如果一个Bean当中存在属性没有加载,会在第一次调用getBean()方法的时候报错,而ApplicationContext会在读取Xml文件后,如果配置文件没有错误,就会将所有的Bean加载到内存中,缺点就是在Bean较多的时候比较占内存,程序启动较慢。

Bean XML配置(理解)

基础两个包:org.springframework.beans和org.springframework.context
Bean常用配置项:
id、class、scope、constructor-arg、property、Autowiring mode、lazy-initialization mode、Initialization/destruction method
Bean作用域:
singleton(单例,默认)、prototype(每次请求)、request(当前request内有效)、session(当前session内有效)、global session(基于portlet的web中有效)
Bean生命周期:
定义、初始化、使用、销毁
基本配置
一个<bean>通常需要定义id与class属性,class属性用于指定对应的java类,id属性用于Bean相互访问。
如:<beanid=”example” class=”example.ExampleBean”></bean>
相当于ExampleBeanexample = new ExampleBean();
若根据类型获取Bean则不需配置id,class是必须的!
工厂模式
<bean id=”example”class=”examples.MyFactoryBean”
factory-method=”createInstance”>
相当于:example =examples.MyFactoryBean.createInstance();
 
<bean id=”example” factory-bean=”myFactoryBean”
factory-method=”createInstance”>
相当于:example =myFactoryBean.createInstance();
 
构造函数<constructor-arg>
如果JavaBean构造函数有参数。
<bean id=”example”class=”examples.ExampleBean”>
       <constructor-argname=”anotherBean”><ref bean=”anotherBean”/></constructor-arg>
       <constructor-argname=”i”><value>1</value></constructor-arg>
</bean>
相当于:
public ExampleBean(AnotherBeananotherBean,int i){
              this.anotherBean=anotherBean;
              this.i=I;
}
配置属性<property>
Spring通过Bean的setter方法设置属性,需要由Spring注射的属性一般都具有公共的getter和setter方法。
如:
<bean id … class ...>
       <propertyname=”…” value=”…”></property>
</bean>
设置对象属性使用<ref>
<ref>的bean属性为目标<bean>的id属性,local属性只能使用本配置文件,parent属性只能使用父配置文件。
 
<list>配置java.util.List类型属性
<property name=”somelist”><list><value>String/Integer..</value></list></property>
<set>配置java.util.Set类型属性
<map> java.util.Map
 
配置Properties属性
使用<props><prop>配置Properties属性,<props>配置一个Properties对象,<prop>配置一条属性,属性key配置索引,如:
<property name=”props”>
       <props>
              <propkey=”url”>http:...</prop>
              <propkey=”name”>webName</prop>
       </props>
</property>
相当于:
Properties props=newProperties(){put(“url”,”http:..”);put(“name”,”..”);
}
bean.setProps(props);
<idref>与<ref>区别:<idref>只有bean和local属性,没有parent属性。Spring加载XML配置文件时,会检测<idref>配置的Bean是否存在,而<ref>只会在第一次调用时检测。
 
依赖对象depends-on
Spring会默认按照配置文件里面Bean配置先后顺序实例化。但实例化A前需要实例化B,可以使用depends-on。
<bean id=”a” class=”A” depends-on=”b”></bean>
<bean id=”b” class=”B”></bean>
 
初始化方法init-method
方法一:实现org.springframework.beans.factory.InitializingBean接口,覆盖afterPropertiesSet()方法
方法二:配置init-method
<bean id=”c” class=”C” init-method=”init”></bean>
相当于:
C c = new C();c.init();
 
销毁方法destroy-method
例如有的对象如数据库连接,在使用完毕后会close()释放资源。
方法一:实现org.springframework.beans.factory.DisposableBean接口,覆盖destroy()方法。
方法二:使用destroy-method配置。Spring在注销这些资源时会调用destroy-method里配置的方法。
<bean id=”dataSource” class=”..” destroy-method=”close”>...</bean>
 
在<beans>标签中定义全局初始化和销毁方法,方法也是定义在Bean对应的类中。default-init-method="..."
default-destroy-method="..."关于bean初始化和销毁同时使用的注意情况:
1,默认全局的初始化和销毁方法;
2,实现接口的初始化和销毁方法;
3,配置文件中配置初始化和销毁方法;
这三个方法同时使用时,1默认的则不执行,而23两种都会执行,并且是2实现接口的方式先于配置中3的执行。
自动装配autowire
不用配置<ref>而根据某种规则在Bean容器中查找自动配置属性。
在<beans>标签中default-autowire="byName"No:不做任何操作,默认
byname:根据属性名自动装配(Bean的id)。
byType:容器中存在一个与指定属性类型相同的bean,将自动装配;如果存在多个类型,抛出异常。
Constructor:与byType类似,应用于构造器参数。
依赖检查dependency-check
启动时检查Bean的属性配置有误。
 

Bean 注解配置(重要)

Spring 2.x开始支持注解配置。

声明Bean的注解:

@Component@Repository@Service@Controller

@Component,通用注解,可用于任何Bean,没有明确的角色。
@Repository,通常用于注解DAO类,即持久层
@Service,通常用于注解Service类,即服务层
@Controller,通常用于Controller类,即控制层(MVC)
为了能够检测这些类并注册相应的Bean,需要扫描对应的包下的java类实现注册Bean<context:component-scan base-package="annotations">
</context:component-scan>
@Scope("prototype")//声明作用域@Service
@Scope("prototype")
public class DemoPrototypeService {

注入Bean的注解:

@Autowired

Spring提供的注解,可用于成员变量、构造器、setter方法,自动注入,若找不到会抛出异常,可以@Autowired(required=false),@Autowired必要属性建议使用@Required注解。
@Autowired是由Spring BeanPostProcessor处理的,所以这个类型只能用XML或者Spring的@Bean。
@Order注解可以实现数组有序。@Order(1)
@Component
public class BeanImplTwo implements BeanInterface {}@Autowired等同于XML配置中autowire=”byType”。
@Resource等同于XML配置中autowire=”byName”。

@Required

适用于setter方法,表示bean属性必须在配置时被填充,通过在bean定义或通过自动装配一个明确的属性值。
@Inject:JSR-330提供的注解
@Resource:JSR-250提供的注解
可以注解在set 方法上或者属性上。

@Qualifier

按类型自动装配可能多个bean实例的情况,可以使用Spring的@Qualifier注解缩小范围(或指定唯一)。也可以用于注解集合类型变量。
如:@Autowired
@Qualifier("beanImplTwo")
private BeanInterface beanInterface;指定该成员变量为Id为“beanImplTwo”的bean。
如果通过名字进行注解注入,一般使用JSR-250的@Resource注解。
 
<context:component-scan>与<context:annotation-config>区别:
<context:annotation-config> 是用于激活那些已经在spring容器里注册过的bean(无论是通过xml的方式还是通过package sanning的方式)上面的注解,是一个注解处理工具。
<context:component-scan>除了具有<context:annotation-config>的功能之外,<context:component-scan>还可以在指定的package下扫描以及注册javabean 。
详情见http://blog.csdn.net/baple/article/details/16864835

JSR-250@Resource

@Resource有一个name属性,默认Spring解释该值作为被注入bean的名称,若没有显示指明,则为setter方法或属性名得出。
@PostConstruct&@PreDestroy,初始化回调和销毁回调
如:@Service
public class JSR250WayService {
    @PostConstruct
    public void init(){System.out.println("JSR250_init()");}
    @PreDestroy
    public void destroy(){System.out.println("JSR250_destroy()");}

JSR-330@Inject

使用JSR330需要依赖javax.inject包
@Inject等效于@Autowire,可以使用于类、属性、方法、构造器。
@Named,使用特定名称进行依赖注入,第二种使用方式类似于@Component
 

Bean Java配置(重要)

Spring 3.x到4.x和Spring Boot都推荐使用Java配置,可以完全代替XML配置。
通过@Configuration@Bean来实现。
@Configuration,声明当前类是一个配置类,@ComponentScan(“com.example”)自动扫描包名下所有注册的Bean,相当于一个Spring配置的xml文件
@Bean注解在方法上,声明当前方法返回值为一个Bean。
 
一般全局配置使用Java配置(数据库、MVC等),业务Bean配置使用注解配置(@Service、@Component、@Repository、@Controller)。

@Bean

标识一个用于配置和初始化一个由Spring IoC容器管理的新对象的方法,类似于XML配置文件的<bean>@Configuration
@ComponentScan("com.sunlin.test_SpringByMaven.prepost")
public class PrePostConfig {
    @Bean(initMethod = "init",destroyMethod = "destroy")
    BeanWayService beanWayService(){return new BeanWayService();}
}name默认为方法名,initMethod指定为StringStore类中定义的方法,销毁方法为destroyMethod。@Scope("prototype")//声明作用域
 

Spring-IoC注入方式和适用场景

XML方式:1、Bean实现类来自第三方类库,如:DataSource等;2、需要命名空间配置,如:context,aop,mvc等。
注解方式:项目中自身开发使用的类,可直接在代码中使用注解,如:@Service,@Controller等
Java配置类:需要通过代码控制对象创建逻辑的场景,如:自定义修改依赖类库。

Spring EL和资源调用(properties文件)

从资源文件中加载资源文件的配置,在XML文件中配置:
<context:property-placeholderlocation="classpath:config.properties"/>多个文件可以使用“,”号隔开:
<context:property-placeholderlocation="classpath:config1.properties,classpath:config2.properties"/>
Spring主要在@Value的参数中使用表达式。@Configuration
@ComponentScan("com.sunlin.test_SpringByMaven.el")
@PropertySource("classpath:test.properties")//配置文件
public class ELConfig {
    @Value("直接注入的信息")//注入普通字符串
    private String normal;
    @Value("#{systemProperties['os.name']}")//注入操作系统属性
    private String osName;
    @Value("#{T(java.lang.Math).random()}")//注入表达式结果
    private double randomNumber;
    @Value("#{demoService.another}")//注入其他Bean的属性
    private String fromAnother;
    @Value("classpath:test.txt")//注入文件资源
    private Resource testFile;
    @Value("http://www.baidu.com")//注入网址资源
    private Resource testUrl;
    @Value("${name}")//注入配置文件对应的键值
    private String bookName;
    @Autowired
    private Environment environment; //Properties获取方式二
    @Bean//Properties获取方式一
    public static PropertySourcesPlaceholderConfigurer propertyConfigure(){
        return new PropertySourcesPlaceholderConfigurer();
    }

    public void outputResource(){
        try {
            System.out.println(normal);
            System.out.println(osName);
            System.out.println(randomNumber);
            System.out.println(fromAnother);
            System.out.println(IOUtils.toString(testFile.getInputStream()));
            System.out.println(IOUtils.toString(testUrl.getInputStream()).substring(0,4));
            System.out.println("Properties获取方式一:"+bookName);
System.out.println("Properties获取方式二:"+environment.getProperty("name"));
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

@ImportResource

Spring Boot的配置类中,配置如下:@Configuration
@ImportResource("classpath:config.xml")
public class StoreConfig {
  
   @Value("${url}")
   private String url;

   @Value("${jdbc.username}")//注意变量名会冲突的情况
   private String username;

   @Value("${password}")
   private String password;

   @Bean
   public MyDriverManager myDriverManager() {
      return new MyDriverManager(url, username, password);
   }
}
 

事件ApplicationEvent

Spring的事件(Application Event)为Bean与Bean之间的消息通信提供了支持。当一个Bean处理完一个任务后,希望另外一个Bean知道并能做相应的处理。
流程:
(1)自定义事件,继承ApplicationEventpublic class DemoEvent extends ApplicationEvent {
    private static final long serialVersionUID=1L;
    private String msg;

    public DemoEvent(Object source,String msg) {
        super(source);
        this.msg=msg;
    }

    public String getMsg() {return msg;}

    public void setMsg(String msg) {this.msg = msg;}
}(2)定义事件监听器,实现ApplicationListener接口@Component
public class DemoListener implements ApplicationListener<DemoEvent>{//指定监听的事件类型
    @Override
    public void onApplicationEvent(DemoEvent event) {
        String msg = event.getMsg();
        System.out.println(msg);
    }
}(3)使用容器发布事件@Component
public class DemoPublisher {
    @Autowired//注入ApplicationContext来发布事件
    ApplicationContext applicationContext;
    public void publish(String msg){
        applicationContext.publishEvent(new DemoEvent(this,msg));//发布事件
    }
}配置类@Configuration
@ComponentScan("com.sunlin.test_SpringByMaven.event")
public class EventConfig {
}运行@Test
public void test_event(){
    AnnotationConfigApplicationContext context =
            new AnnotationConfigApplicationContext(EventConfig.class);
    DemoPublisher demoPublisher = context.getBean(DemoPublisher.class);
    demoPublisher.publish("信息");
    context.close();
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: