Spring学习笔记
Spring学习笔记
1、Spring的组成架构:
Core和Beans模块中,BeanFactory是一个工厂模式的实现。
Context模块中,ApplicationContext接口是该模块的焦点。
Data Access/Intergration层:
OXM模块为JAXB、Castor、XMLBeans等提供一个支持Object/XML映射的接口。
JMS模块提供关于消息的生产和消费相关的技术。
2、Spring XML文件的配置:
<beans>
<bean id=”” class=”全类名”>
<property name=”” value=””></property>
</bean>
</beans>
配置bean时候,class:bean的全类名,通过反射的方式在IOC容器中创建Bean,所以要求Bean中必须有无参的构造器。
id:标识容器中的bean,值唯一。
//创建Spring的IOC容器对象即实例化,其中ClassPathXmlApplicationContext是ApplicationContext接口的实现类,该实现类从类路径加载配置文件
ApplicationContext ctx =new ClassPathXmlApplicationContext(“configName.xml”);
//获取bean的实例
ctx.getBean(“id值”);
ApplicationContext是BeanFactory的子接口,代表IOC容器。在SpringIOC容器读取Bean配置创建Bean实例之前,必须对它进行实例化,只有在容器实例化后,才可从IOC容器中获取Bean实例并使用。
3、依赖注入方式:属性注入、构造器注入
(1)属性注入:即通过setter方法注入Bean的属性值或依赖的对象,属性注入使用<property>元素,使用name属性指定Bean的属性名称,value属性或者<value>子节点指定属性值
属性注入是实际应用中最为常见的注入方式
<beans>
<bean id=”” class=”全类名”>
<property name=”userName” value=”wuRong”></property>
</bean>
</beans>
(2)构造方法注入:通过构造方法注入Bean的属性值或者依赖的对象,它保证了Bean实例在实例化后就可以使用。
构造器注入在<constructor-arg>元素里声明属性,<constructor-arg>中没有name属性。
<bean id=”” class=””>
<constructor-arg value=”属性1”></constructor-arg>
<constructor-arg value=”属性2”></constructor-arg>
<constructor-arg value=”属性n”></constructor-arg>
</bean>
当一个类需要引用另一个类的时候,xml文件中的bean配置方法如下:
<beans>
<bean id=”” class=”全类名”>
<property name=”” value=””></property>
<property name=”引用类对象名” ref=”引用类的beanId”></property>
</bean>
</beans>
属性需要先初始化,然后才可以级联属性赋值,否则会有异常。
集合属性的配置:<list> <set> <map>
<list>集合配置方式:
<bean id=”” class=””>
<property name=”” value=””></property>
<property name=”listName” >
<list>
<ref bean=”元素1”/>
<ref bean=”元素2”/>
<ref bean=”元素3”/>
</list>
</property>
</bean>
<map>集合配置方式:
<bean id=”” class=””>
<property name=”” value=””></property>
<property name=”mapName” >
<map>
<entry key=”” value-ref=””></entry>
<entry key=”” value-ref=””></entry> //键值对
</map>
</property>
</bean>
配置properties属性值:使用props和prop子节点为属性赋值
<bean id=”” class=””>
<property name=”properties” >
<props>
<prop key=”user” >root</prop>
<prop key=”password” >123456</prop>
<prop key=”driverClass” >com.mysql.jdbc.Driver</prop>
</ props>
</property>
</bean>
还可以通过p命名空间,为bean的属性赋值,需要先导入p命名空间。
<bean id=”person” class=”com.spring.Person” p:age=”” p:name=””></bean>
其中Person是一个类,age和name是Person类中的成员属性,这种方式更加简洁。
4、自动装配:XML配置里的Bean自动装配,SpringIOC容器可以自动装配Bean,需要做的仅仅是在<bean>的autowire属性里指定自动装配的模式。
byType: 根据类型自动装配,若IOC容器中有多个与目标Bean类型一致的Bean,在这种情况下,Spring将无法判断哪个Bean最合适该属性,所以不能执行自动装配。
byName:根据名称自动装配,必须将目标Bean的名称和属性名设置的完全相同。根据bean的名字和当前bean的setter风格的属性名进行自动装配。若有匹配的,则进行自动匹配,若没有匹配的则不装配。
Constructor:通过构造器自动装配,当Bean中存在多个构造函数时候,此种自动装配方式将会很复杂,不推荐使用。
5、Bean配置的继承:使用bean的parent,被继承的bean称为父bean,继承这个父类的bean被称为子bean;
子bean从父bean中继承配置,包括bean的属性配置;
子bean也可以覆盖从父bean继承过来的配置;
父bean可以作为配置模板,也可以作为bean实例。若只想把父bean作为模板,可以设置<bean>的abstract属性为true,这样Spring将不会实例化这个Bean。
6、依赖Bean配置:Spring允许通过depend-on属性设定Bean前置依赖的bean,前置依赖的bean会在本bean实例化之前创建好;
如果前置依赖于多个bean,则可以通过逗号,空格的方式前置bean的名称。
7、bean的作用域:prototype原型,每次创建bean都会返回一个新的bean实例。
singleton单例,默认的作用域,容器初始化化时就已经创建了bean实例,在整个容器的生命周期中都只有这一个实例。
Bean的作用域有5种:singleton、prototype、request、session和global session。如果一个Bean的作用域为singleton,那么Spring IoC容器就只会存在一个共享的Bean实例,并且所有对Bean的请求,只要id与该Bean匹配,就只会返回Bean的同一个实例。换言之,当一个Bean定义设置为singleton作用域时,Spring IoC只会创建该Bean定义的唯一实例。这个单一实例会被存储在单例缓存中,并且所有针对该Bean的后续请求和引用都将返回被缓存的对象实例。
Prototype作用域的Bean会导致在每次对该Bean请求(将其注入到另一个Bean中,或者以程序调用的方式调用容器的getBean()方法)时,都会创建一个新的Bean实例。根据经验,对有状态的Bean使用prototype作用域,对无状态的Bean使用singleton作用域。
8、导入外部属性文件:
<context:property-placeholder location=”classpath:db.properties”/>
//使用外部化属性文件的属性
<property name=”user” value=”${user}”></property>
<property name=”password” value=”${ password }”></property>
其中db.properties为外部属性配置文件名称,user和password都是该文件中配置的属性名。
9、Spring表达式语言:SpEL,它是一个支持运行时查询和操作对象图的强大的表达式语言;
语法类似于EL:SpEL使用#{…}作为定界符,所有在大框号中的字符都被认为是SpEL;
SpEL为bean的属性进行动态赋值提供了便利。
通过SpEL可以实现一下功能:
----通过bean的id对bean进行引用;
----调用方法以及引用对象中的属性;
----计算表达式的值;
----正则表达式的匹配。
//引用其他对象:
<property name=”prefix” value=”#{prefixGenerator}”></property>
//引用其他对象的属性
<property name=”suffix” value=”#{sequenceGenerator.suffix}”></property>
//调用其他方法
<property name=”prefix” value=”#{prefixGenerator.toString()}”></property>
//方法的连接操作
<property name=”prefix” value=”#{prefixGenerator.toString().toUpperCase()}”></property>
10、IOC容器中Bean的生命周期方法:
SpringIOC容器对Bean的生命周期进行管理的过程如下:
---通过构造器或工厂方法创建bean实例;
---为bean的属性设置值和对其他bean的引用;
---调用bean的初始化方法;
---bean可以使用了;
---当容器关闭时,调用bean的销毁方法。
在bean的申明里设置init-method和destory-method属性,为bean指定初始化和销毁方法。
<bean id=”car” class=”com.spring.bean.Car” init-method=”初始化方法名” destroy-method=”销毁方法名”>
<property name=”” value=””></property>
</bean>
类Car中定义了初始化方法init()和销毁方法destory(),方法名叫什么无所谓,但是一定要和bean配置文件中名字一样。
11、Bean后置处理器:它允许在调用初始化方法前后对Bean进行额外的处理。
对Bean后置处理器而已,需要实现Inerface BeanPostProcessor接口,在初始化方法被调用前后,Spring将把每个Bean实例分别传递给上述接口的下面两个方法:
postProcessAfterInitialization(Object bean,String beanName)
postProcessBeforeInitialization(Object bean,String beanName)
添加Bean的后置处理器后Bean的生命周期:SpringIOC容器对Bean的生命周期进行管理的过程:
---通过构造器或工厂方法创建bean实例;
---为bean的属性设置值和对其他bean的引用;
---将Bean实例传递给Bean后置处理器的postProcessBeforeInitialization()方法;
---调用bean的初始化方法;
---将Bean实例传递给Bean后置处理器的postProcessAfterInitialization()方法;
---bean可以使用了;
---当容器关闭时,调用bean的销毁方法。
12、基于注解的bean配置方式(基于注解配置bean,基于注解来装配Bean的属性)
在classpath中扫描组件:组件扫描,Spring能够从classpath下自动扫描,侦测和实例化具有特定注解的组件。特定组件包括:
--- @Component:基本注解,标识一个受Spring管理的组件
--- @Responsitory:标识持久层组件
--- @Service:标识服务层(业务层)组件
--- @Controller:组件表现层组件
对于扫描到的组件,Spring有默认的命名策略:使用非限定类名,第一个字母小写。也可以在注解中通过value属性值标识组件的名称。
当在组件类上使用了特定的注解之后,还需要在Spring的配置文件中申明<context:component-scan>:
--- base-package属性指定一个需要扫描的基类包,Spring容器将会扫描这个基类包里及子包中所有的类;
--- 当需要扫描多个包时,可以使用逗号隔开。
--- 如果仅仅希望扫描特定的类而非基包下的所有类,可使用resource-pattern属性过滤特定的类,示例:
<context:component-scan
base-package=”com.zte.spring.beans”
resource-pattern=”autowire/*.class”>
</ context:component-scan>
--- <context:include-filter>子节点表示要包含的目标类
--- <context:exclude-filter>子节点表示要排除在外的目标类
--- <context:component-scan>下可以拥有若干个<context:include-filter>和<context:exclude-filter>子节点
组件装配:<context:component-scan>元素还会自动注册AutowiredAnnoationBeanPostProcessor实例,该实例可以自动装配具有@Autowired和@Resource、@Inject注解的属性。
13、泛型依赖注入:
Spring4.x中可以为子类注入子类对应的泛型类型的成员变量的引用。
14、Spring AOP面向切面编程
动态代理设计模式的原理:使用一个代理将对象包装起来,然后用该代理对象取代原始对象,任何对原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原始对象上。
AOP的主要编程对象是切面(aspect),而切面模块快横切关注点。
在应用AOP编程时,仍然需要定义公共设施,但是可以明确的定义这个功能在哪里,以什么方式应用,并且不必修改受影响的类,这样一来横切关注点就被模块化到特殊的对象(切面)中了。
AOP的好处:
--- 每个事物逻辑位于一个位置,代码不分散,便于维护和升级;
--- 业务模块更简洁,只包含核心业务代码。
几个基本AOP术语:
--- 切面Aspect:横切关注点(跨越应用程序多个模块的功能)被模块化的特殊对象;
--- 通知Advice:切面必须要完成的工作;
--- 目标Target:被通知的对象;
--- 代理Proxy:向目标对象应用通知之后创建的对象;
--- 连接点JoinPoint:程序执行的某个特定位置;
--- 切点pointCut:每个类都拥有多个连接点,连接点是程序类中客观存在的事务。AOP通过切点定位到特定的连接点。连接点相当于数据库中的记录,切点则相当于查询条件。切点和连接点不是一对一的关系,一个切点匹配多个连接点,切点通过org.springframework.aop.Pointcut接口进行描述,它使用类和方法作为连接点的查询条件。
AspectJ:是java社区里面最完整最流行的框架,在Spring2.0以上的版本中,可以使用AspectJ注解和xml配置的方式进行使用。
--- 要在Spring中使用AspectJ注解,必须在classpath下包含AspectJ类库,aopalliance.jar、aspectj.weaver.jar、spring-aspectjs.jar
--- 将aop Schema添加到<beans>根元素中;
--- 要在SpringIOC容器中启动AspectJ注解支持,只要在Bean配置文件中定义一个空的XML元素<aop:aspectj-autoproxy>;
--- 当SpringIOC容器侦测到Bean配置文件中的<aop:aspect-autoproxy>元素时,会自动为与AspectJ切面匹配的Bean创建代理。
Spring AOP小结:
1)加入jar包;
2)在配置文件中加入AOP的命名空间;
3)基于注解的方式:
--- 在配置文件中加入如下配置<aop:aspect-autoproxy>
--- 把横切关注点的代码抽象到切面的类中,切面首先是一个IOC中的bean,即加入@Component注解;
--- 切面还需要加入@Aspect注解;然后在类中申明各种通知(申明一个方法,然后在方法上加上如下通知注解):
@Before:前置通知,在方法执行之前执行;
@After:后置通知,在方法执行之后执行;
@AfterRunning:返回通知,在方法返回结果之后执行;
@AfterThrowing:异常通知,在方法抛出异常之后;
@Around:环绕通知,围绕着方法执行。
--- 可以在通知方法中申明一个类型为JoinPoint的参数,然后就是访问连接细节,如方法名和参数值。
使用@Order(1)来指定多个切面的优先级,值越小优先级越高。
Spring的原理:
Spring的一个重要的设计模式就是抽象工厂方法和模板方法模式。另外AOP面向方面编程使用的设计模式是动态代理模式:
代理有两种方式:
1)静态代理:
针对每一个具体的类分别编写代理类;
针对一个接口编写一个代理类。
2)动态代理:
针对一个方面编写一个InvocationHandler,然后借用JDK中的反射包中的Proxy类为各种接口动态生成相应的代理类。
动态代理和静态代理的区别?
静态代理:由程序员创建,再对其编译。在程序运行之前.class文件已经存在了。动态代理:在程序运行时,运用反射的机制动态创建而完成。无需程序员手动编写代码,利用jdk的动态代理机制即可,不仅简化了编程工作,且提高了软件的可扩展性,因为java的反射机制可以生成任意类型的动态代理。 动态代理使用场景:不允许直接访问某些类,对访问要做特殊处理;或者对原始方法进行统一的扩展,例如日志的记录。
Spring IOC使用了单例模式,在使用时只创建一个全局对象,也可以在配置文件中进行多实例的配置。
Spring的事务管理:
事务就是对一系列的数据库操作(比如插入多条数据),进行统一的提交或者回滚操作,如果插入成功则一起成功,如果插入失败则一起失败。这样可以防止脏数据。