Spring学习笔记

spring的核心模块(了解core就好)

这里写图片描述

core Container,spring最核心的模块IOC就在这里体现
Spring Core:核心容器提供了Spring的基本功能。核心容器的核心功能是用Ioc容器来管理类的依赖关系.Spring采用的模式是调用者不理会被调用者的实例的创建,由Spring容器负责被调用者实例的创建和维护,需要时注入给调用者。这是目前最优秀的解耦模式。
Spring AOP:Spring的AOP模块提供了面向切面编程的支持。SpringAOP采用的是纯Java实现。Spring AOP采用基于代理的AOP实现方案,AOP代理由Ioc容器负责生成、管理,依赖关系也一并由Ioc容器管理,尽管如此,Spring Ioc容器并不依赖于AOP,这样我们可以自由选择是否使用AOP。
Spring ORM:提供了与多个第三方持久层框架的良好整合。
Spring Context:它是一个配置文件,为Spring提供上下文信息,提供了框架式的对象访问方法。Context为Spring提供了一些服务支持,如对国际化(i18n)、电子邮件、校验和调度功能。

spring的IOC实现

所谓IoC,对于spring框架来说,就是由spring来负责控制对象的生命周期和对象间的关系。(由Spring来为你创建对象
XML配置Bean实例化的三种方式:
1、第一种 使用类的无参数构造创建(重点)
2、第二种 使用静态工厂创建(创建静态的方法,返回类对象)
bean里的属性factory- method来指定静态工程的实例化方法,并且bean的class属性是指向静态工程的类
3、第三种使用实例工厂创建(创建不是静态的方法,返回类对象)
创建两个bean,分别指向实例化的类和工厂方法,而且实例化类的bean上的属性factory-bean指向工厂bean的ID,factory- method为工厂bean的实例化方法。

注解参考下文的spring的注解。

spring的DI

属性注入
1、使用set注入

<property name="" value=""></property>

2、有参数构造注入

<constructor-arg name="" value=""></constructor-arg>

3、注入对象类型

<property name="" ref="注入对象的ID"></property>

4、注入复杂属性类型

//数组
<property name="arrs">
<list>
<value> </value>
</list>
</property>

//list
<property name="list">
<list>
<value> </value>
</list>
</property>

//map
<property name="map">
<map>
<entry key="" value=""> </entry>
</map>
</property>

//properties
<property name="map">
<map>
<prop key="" >XXX</entry>
</map>
</property>

bean的自动装配

自动装配有3中方式:
1.根据名称自动装配(byName)。因为spring 容器中Bean的名称是唯一的,所以不会产生歧义,推荐使用这种方式。
2.根据类型自动装配(byType)。在Spring容器中可能会找到多个跟需要注入的bean的类型相同的Bean,所以会产生歧义,Spring容器不知道注入哪个Bean,这时会抛出异常。
3.根据构造器自动装配(constructor)。

XML配置文件的自动装配
即是通过bean元素的autowire属性来设置四种自动装配类型
例如:

<bean id = "auto" class = "com.wang.AutoClass" autowire="byType" />

注解的自动装配
下文的spring注解基本上就是注解的自动装配。

springbean的作用域

当定义一个bean 在Spring里,我们还能给这个bean声明一个作用域。它可以通过bean 定义中的scope属性来定义。如当Spring要在需要的时候每次生产一个新的bean实例,bean的scope属性被指定为prototype。另一方面,一个bean每次使用的时候必须返回同一个实例,这个bean的scope 属性 必须设为 singleton。

singleton : bean在每个Spring ioc 容器中只有一个实例。
prototype:一个bean的定义可以有多个实例。
request:每次http请求都会创建一个bean,该作用域仅在基于web的Spring ApplicationContext情形下有效。
session:在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。
global-session:在一个全局的HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。
缺省(默认)的Spring bean 的作用域是Singleton。

spring注解

对于XML文件,注解型的配置依赖于通过字节码元数据装配组件,而非尖括号的声明。开发者通过在相应的类,方法或属性上使用注解的方式,直接组件类中进行配置,而不是使用xml表述bean的装配关系。

注解装配在默认情况下是不开启的,为了使用注解装配,我们必须在Spring配置文件中配置 元素。
相关注解:
@Autowired
@Autowired 注释,它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。
Spring 通过一个 BeanPostProcessor 对 @Autowired 进行解析,所以要让@Autowired 起作用必须事先在 Spring 容器中声明 AutowiredAnnotationBeanPostProcessor Bean。可以使用简化配置 。

当 Spring 容器启动时,AutowiredAnnotationBeanPostProcessor 将扫描 Spring 容器中所有 Bean,当发现 Bean 中拥有@Autowired 注释时就找到和其匹配(默认按类型匹配)(byType)的 Bean,并注入到对应的地方中去。按照上面的配置,Spring 将直接采用 Java 反射机制对 Boss 中的 car 和 office 这两个私有成员变量进行自动注入。所以对成员变量使用@Autowired 后,您大可将它们的 setter 方法(setCar() 和 setOffice())从 Boss 中删除。

Spring 容器中配置了两个类型为 Office 类型的 Bean,当对 Boss 的 office 成员变量进行自动注入时,Spring 容器将无法确定到底要用哪一个 Bean,因此异常发生了。Spring 允许我们通过 @Qualifier 注释指定注入 Bean 的名称,这样歧义就消除了。

@Qualifier
@Autowired 可以对成员变量、方法以及构造函数进行注释,而@Qualifier 的标注对象是成员变量、方法入参、构造函数入参。正是由于注释对象的不同,所以 Spring 不将 @Autowired 和@Qualifier 统一成一个注释类。

@Resource
@Resource 的作用相当于 @Autowired,只不过 @Autowired 按 byType 自动注入,面@Resource 默认按 byName 自动注入罢了。@Resource 有两个属性是比较重要的,分别是 name 和 type,Spring 将@Resource 注释的 name 属性解析为 Bean 的名字,而 type 属性则解析为 Bean 的类型。所以如果使用 name 属性,则使用 byName 的自动注入策略,而使用 type 属性时则使用 byType 自动注入策略。如果既不指定 name 也不指定 type 属性,这时将通过反射机制使用 byName 自动注入策略。
context:component-scan base-package=”com.persia”>

<context:component-scan base-package="com.persia">
<!-- 开启组件扫描 -->
</context:component-scan>

@Repository通常作用在DOA层,但是目前该功能与 @Component 相同。
@Component 是一个泛化的概念,仅仅表示一个组件 (Bean) ,可以作用在任何层次。
@Service 通常作用在业务层,但是目前该功能与 @Component 相同。
@Constroller 通常作用在控制层,但是目前该功能与 @Component 相同。

!!!!@Scope 指定 Bean 的作用范围

spring的配置文件

一些比较重要的配置:

<context:component-scan base-package="com.persia">
**<!-- 开启组件扫描 -->**
</context:component-scan>

<context:annotation-config>
**<!--开启注解处理器-->**
</context:annotation-config>

**<!-- 配置数据源 -->**   
  <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">   
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>   
    <property name="url" value="jdbc:mysql://localhost:3306/test?useUnicode=true&amp;characterEncoding=utf-8"/>   
    <property name="username" value="root"/>   
    <property name="password" value=""/>   
     <!-- 连接池启动时的初始值 -->   
     <property name="initialSize" value="1"/>   
     <!-- 连接池的最大值 -->   
     <property name="maxActive" value="500"/>   
     <!-- 最大空闲值.当经过一个高峰时间后,连接池可以慢慢将已经用不到的连接慢慢释放一部分,一直减少到maxIdle为止 -->   
     <property name="maxIdle" value="2"/>   
     <!--  最小空闲值.当空闲的连接数少于阀值时,连接池就会预申请去一些连接,以免洪峰来时来不及申请 -->   
     <property name="minIdle" value="1"/>   
  </bean>  

  **<!-- 配置事务管理器-->**   
 <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">   
    !!!!!**<property name="dataSource" ref="dataSource"/>**   
  </bean>  

  **<!-- 配置业务bean -->**
    <bean id="personService" class="com.persia.service.impl.PersonServiceImpl">
    <property name="ds" ref="dataSource"></property>
  </bean>

  **<!-- 采用@Transactional注解方式来使用事务 -->**   
  <tx:annotation-driven transaction-manager="txManager"/> 

spring的AOP实现

AOP相关概念:
1 aop:面向切面(方面)编程,扩展功能不修改源代码实现

2 AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码

3 aop底层使用动态代理实现
(1)第一种情况,有接口情况,使用动态代理创建接口实现类代理对象
(2)第二种情况,没有接口情况,使用动态代理创建类的子类代理对象

操作术语:
Joinpoint(连接点): 类里面可以被增强的方法,这些方法称为连接点

Pointcut(切入点):所谓切入点是指我们要对哪些Joinpoint进行拦截的定义.

Advice(通知/增强):所谓通知是指拦截到Joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)

Aspect(切面): 是切入点和通知(引介)的结合

Introduction(引介):引介是一种特殊的通知在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field.

Target(目标对象):代理的目标对象(要增强的类)

Weaving(织入):是把增强应用到目标的过程.(把advice 应用到 target的过程)

Proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类

AOPXML配置操作

AOP注解操作

AOP实现原理:

jdk动态代理实现:
JDK的动态代理依靠接口实现,如果有些类并没有实现接口,则不能使用JDK代理

public interface BookFacade {  
    public void addBook();  
}  

public class BookFacadeImpl implements BookFacade {  

    @Override  
    public void addBook() {  
        System.out.println("增加图书方法。。。");  
    }  

}  

//BookFacadeProxy.java  

package net.battier.proxy;    
import java.lang.reflect.InvocationHandler;  
import java.lang.reflect.Method;  
import java.lang.reflect.Proxy;  

/** 
 * JDK动态代理代理类 
 *  
 * @author student 
 *  
 */  
public class BookFacadeProxy implements InvocationHandler {  
    private Object target;  
    /** 
     * 绑定委托对象并返回一个代理类 
     * @param target 
     * @return 
     */  
    public Object bind(Object target) {  
        this.target = target;  
        //取得代理对象  
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),  
                target.getClass().getInterfaces(), this);   //要绑定接口(这是一个缺陷,cglib弥补了这一缺陷)  
    }  

    @Override  
    /** 
     * 调用方法 
     */  
    public Object invoke(Object proxy, Method method, Object[] args)  
            throws Throwable {  
        Object result=null;  
        System.out.println("事物开始");  
        //执行方法  
        result=method.invoke(target, args);  
        System.out.println("事物结束");  
        return result;  
    }  

}  

import net.battier.proxy.BookFacadeProxy;  

public class TestProxy {  

    public static void main(String[] args) {  
        BookFacadeProxy proxy = new BookFacadeProxy();  
        BookFacade bookProxy = (BookFacade) proxy.bind(new BookFacadeImpl());  
        bookProxy.addBook();  
    }  

}  

cglib动态代理实现
cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。

public class BookFacadeImpl1 {  
    public void addBook() {  
        System.out.println("增加图书的普通方法...");  
    }  
}  

import java.lang.reflect.Method;  

import net.sf.cglib.proxy.Enhancer;  
import net.sf.cglib.proxy.MethodInterceptor;  
import net.sf.cglib.proxy.MethodProxy;  

/** 
 * 使用cglib动态代理 
 *  
 * @author student 
 *  
 */  
public class BookFacadeCglib implements MethodInterceptor {  
    private Object target;  

    /** 
     * 创建代理对象 
     *  
     * @param target 
     * @return 
     */  
    public Object getInstance(Object target) {  
        this.target = target;  
        Enhancer enhancer = new Enhancer();  
        enhancer.setSuperclass(this.target.getClass());  
        // 回调方法  
        enhancer.setCallback(this);  
        // 创建代理对象  
        return enhancer.create();  
    }  

    @Override  
    // 回调方法  
    public Object intercept(Object obj, Method method, Object[] args,  
            MethodProxy proxy) throws Throwable {  
        System.out.println("事物开始");  
        proxy.invokeSuper(obj, args);  
        System.out.println("事物结束");  
        return null;  


    }  

}  

import net.battier.proxy.BookFacadeCglib;  

public class TestCglib {  

    public static void main(String[] args) {  
        BookFacadeCglib cglib=new BookFacadeCglib();  
        BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1());  
        bookCglib.addBook();  
    }  
}  

Spring的事物控制

使用tx标签方式
步骤:

//1、配置事物管理器
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">   
    !!!!!**<property name="dataSource" ref="dataSource"/>**   
  </bean> 

//2、配置事物增强
<!-- 第一种配置事务的方式 ,tx-->
<tx:advice id="txadvice" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="add*" propagation="REQUIRED" rollback-for="Exception" />
        <tx:method name="modify*" propagation="REQUIRED" rollback-for="Exception" />
        <tx:method name="del*" propagation="REQUIRED" rollback-for="Exception"/>
        <tx:method name="*" propagation="REQUIRED" read-only="true"/>
    </tx:attributes>
</tx:advice>

//配置切面
<aop:config>
    <aop:pointcut id="daoMethod" expression="execution(* com.dao.*.*(..))"/>
    <aop:advisor pointcut-ref="daoMethod" advice-ref="txadvice"/>
</aop:config>

Spring的事物传播

Propagation :
key属性确定代理应该给哪个方法增加事务行为。这样的属性最重要的部份是传播行为。有以下选项可供使用:
PROPAGATION_REQUIRED–支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
PROPAGATION_SUPPORTS–支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY–支持当前事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW–新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED–以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER–以非事务方式执行,如果当前存在事务,则抛出异常。

spring解决线程安全的问题

SpringMVC并发访问是否会存在线程安全问题?
对于Struts2来说,因为每次处理一个请求,struts2就会实例化一个对象;这样就不会有线程安全的问题了;

Spring的controller默认是Singleton的,这意味着每一个request过来,系统都会用原有的instance去处理,这样导致两个结果
1、一是我们不用每次创建Controller
2、二是减少了对象创建和垃圾收集的时间;由于只有一个Controller的instance,当多个线程调用它的时候,它里面的instance变量就不是线程安全的了,会发生窜数据的问题。

有几种解决方法:
1、在Controller中使用ThreadLocal变量
2、在spring配置文件Controller中声明 scope=”prototype”,每次都创建新的controller所在在使用spring开发web 时要注意,默认Controller、Dao、Service都是单例的。

ThreadLocal:
ThreadLocal是如何做到为每一个线程维护变量的副本的呢?其实实现的思路很简单:在ThreadLocal类中有一个Map,用于存储每一个线程的变量副本,Map中元素的键为线程对象,而值对应线程的变量副本。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值