Spring学习笔记-IoC

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或Listener

FileSystemXmlApplicationContext 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中读取需要加classpath

ApplicationContext 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)自定义事件,继承ApplicationEvent

public 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();
}

 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值