spring快速入门

来源:互联网 发布:淘宝自定义导航条代码 编辑:程序博客网 时间:2024/06/08 13:42

1.spring简介

Spring是一个开源框架。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 J2EE 应用程序开发提供集成的框架。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。Spring的核心是控制反转(IoC)和面向切面(AOP)。简单来说,Spring是一个分层的JavaSE/EE full-stack(一站式) 轻量级开源框架。贯穿web,dao,service三层的框架。Spring就是一个大工厂(容器),可以将所有对象创建和依赖关系维护,交给Spring管理,spring工厂是用于生成bean。

2.Spring的核心是IoC(控制反转)和AOP(面向切面编程)

2.1 IoC控制反转

之前开发中,直接new一个对象即可。学习spring之后,将由Spring创建对象实例–> IoC 控制反转(Inverse of Control)之后需要实例对象时,从spring工厂(容器)中获得,需要将实现类的全限定名称配置到xml文件中,或者使用注解代替xml。spring的配置文件约定的名字是applicationContext.xml

public interface UserService {    public void addUser();}//---------------------------------------------------public class UserServiceImpl implements UserService {    @Override    public void addUser() {        System.out.println(" add user");    }}//----------------------配置文件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">    <!-- 配置service         <bean> 配置需要创建的对象            id :用于之后从spring容器获得实例时使用的,可以随便取名字,但是最好和类名统一。            class :需要创建实例的全限定类名    --><bean id="userService" class="com.hero.show.UserServiceImpl"></bean></beans>//----------------------------------------------------@Test    public void demo02(){        //从spring容器获得        //1 获得容器        String xmlPath = "com/hero/show/applicationContext.xml";        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);        //2获得内容 --不需要自己new,都是从spring容器获得        UserService userService = (UserService) applicationContext.getBean("userService");        userService.addUser();    }

以上就是spring的IOC,把创建bean实例的权利反转给spring,就叫控制反转。上面的程序实际开发中并不会用到。用来了解原理。

2.2DI依赖注入

DI: Dependency Injection ,依赖注入
is a :是一个,Teacher继承person,老师是一个人。
has a:有一个,成员变量,依赖。五年级三班有一个老师。班级类依赖成员变量 Teacher teacher。

    class B {       private A a;   //B类依赖A类    }依赖:一个对象需要使用另一个对象注入:通过setter方法进行另一个对象实例设置。

例如:

class BookServiceImpl{        //之前开发:接口 = 实现类  (service和dao耦合)        //private BookDao bookDao = new BookDaoImpl();        //spring之后 (解耦:service实现类使用dao接口,不知道具体的实现类)        private BookDao bookDao;        setter方法   }//模拟spring执行过程,为了直观,直接new对象,实际应该使用IOC//创建service实例BookService bookService = new BookServiceImpl()     //使用IoC //创建dao实例BookDao bookDao = new BookDaoImple()                //使用IoC//将dao设置给servicebookService.setBookDao(bookDao);                //这就是DI   
//------------------dao------------------------public interface BookDao {    public void addBook();}public class BookDaoImpl implements BookDao {    @Override    public void addBook() {        System.out.println(" add book");    }}//-------------------service----------------------public interface BookService {     void addBook();}public class BookServiceImpl implements BookService {    // 方式1:之前,接口=实现类//  private BookDao bookDao = new BookDaoImpl();    // 方式2:接口 + setter    private BookDao bookDao;    public void setBookDao(BookDao bookDao) {        this.bookDao = bookDao;    }    @Override    public void addBook(){        this.bookDao.addBook();    }}//---------------------xml--------------------------<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">    <!--         <property> 用于进行属性注入            name: bean的属性名,通过setter方法获得                setBookDao ##> BookDao  ##> bookDao            ref :另一个bean的id值的引用     -->    <!-- 创建service -->    <bean id="bookService" class="com.hero.show.BookServiceImpl">        <property name="bookDao" ref="bookDao"></property>    </bean>    <!-- 创建dao实例 -->    <bean id="bookDao" class="com.hero.show.BookDaoImpl"></bean></beans>//--------------------------------------------------------@Test    public void demo01(){        //从spring容器获得        String xmlPath = "com/hero/show/applicationContext.xml";        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);        BookService bookService = (BookService) applicationContext.getBean("bookService");        bookService.addBook();    }
2.3基于xml装配bean

三种bean实例化方式:默认构造、静态工厂、实例工厂

a.类是默认构造器
必须要有默认构造

<bean id="" class=""> 

b.静态工厂
常用与spring整合其他框架(工具),静态工厂:用于生成实例对象,所有的方法必须是static

<bean id=""  class="工厂全限定类名"  factory-method="工厂的静态方法">

c.实例工厂(非静态工厂)
必须先有工厂实例对象,通过实例对象创建对象。提供所有的方法都是“

<!-- 创建工厂实例 -->    <bean id="myBeanFactory" class="com.hero.show.factory.MyBeanFactory"></bean>    <!-- 获得userservice         * factory-bean 确定工厂实例        * factory-method 确定普通方法    -->    <bean id="userService" factory-bean="myBeanFactory" factory-method="createService"></bean>
2.4作用域

用来确定spring创建bean的个数
singleton:bean是单例,默认值。
prototype:每次从容器拿bean,都是新的对象。
request:每次http请求都会创建一个新的bean。只适用于webApplicationContext环境。
Session:一个Session共享一个bean。不同Session是不同的bean。只适用于webApplicationContext环境。
globalSession:一般用于portlet应用环境。只适用于webApplicationCont。

 <bean id="userServiceId" class="com.hero.show.scope.UserServiceImpl" scope="prototype" ><bean><!--常用的就是singleton 单例,默认值。prototype 多例-->
2.5初始化和销毁

目标方法执行前后执行后,将进行初始化或销毁。

<bean id="" class="" init-method="初始化方法名称"  destroy-method="销毁的方法名称">-----------------------------------------------------public class UserServiceImpl implements UserService {    @Override    public void addUser() {        System.out.println("add user");    }    public void myInit(){        System.out.println("初始化");    }    public void myDestroy(){        System.out.println("销毁");    }}----------------------xml---------------------------------<!--          init-method 用于配置初始化方法,准备数据等        destroy-method 用于配置销毁方法,清理资源等    -->    <bean id="userService" class="com.hero.show.UserServiceImpl"         init-method="myInit" destroy-method="myDestroy" ></bean>---------------------------------------------------------@Test    public void demo02() throws Exception{        //spring 工厂        String xmlPath = "com/hero/show/applicationContext.xml";        System.out.println(-1);        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);        System.out.println(0);        UserService userService = (UserService) applicationContext.getBean("userService");        System.out.println("1");        userService.addUser();        System.out.println("2");        //要求:1.容器在close后销毁方法才执行; 2.必须是单例的//      applicationContext.getClass().getMethod("close").invoke(applicationContext);        // * 此方法接口中没有定义,实现类提供        applicationContext.close();    }//-------------------------输出结果---------------1spring工作,输出控制台信息初始化01addUser2spring关闭,输出控制台信息销毁----------------------------------------由输出结果可以看出,spring读取配置文件创建对象后,初始化方法执行,spring容器close后,销毁方法立即执行
2.6BeanPostProcessor 后处理Bean

BeanPostProcessor接口下有以下两个方法:

Object postProcessBeforeInitialization(Object bean, String beanName)

Object postProcessAfterInitialization( Object bean, String beanName)

spring 提供一种机制,只要实现此接口BeanPostProcessor,并将实现类提供给spring容器,spring容器将自动执行,在初始化方法前执行before(),在初始化方法后执行after() 。spring提供工厂勾子,用于修改实例对象,可以生成代理对象,这个接口是AOP底层实现方法。

模拟
A a =new A();
a = B.before(a) –> 将a的实例对象传递给后处理bean,可以生成代理对象并返回。
a.init();
a = B.after(a);

a.addUser(); //生成代理对象,目的在目标方法前后执行(例如:开启事务、提交事务)

a.destroy()

2.7属性依赖注入

a.构造方法

public class User {    private Integer uid;    private String username;    private Integer age;    public User(Integer uid, String username) {        super();        this.uid = uid;        this.username = username;    }    public User(String username, Integer age) {        super();        this.username = username;        this.age = age;    }//----------------------------------------------    <!-- 构造方法注入         * <constructor-arg> 用于配置构造方法一个参数argument            name :参数的名称            value:设置普通数据            ref:引用数据,一般是另一个bean id值            index :参数的索引号,从0开始 。如果只有索引,匹配到了多个构造方法时,默认使用第一个。            type :确定参数类型        例如:使用名称name            <constructor-arg name="username" value="jack"></constructor-arg>            <constructor-arg name="age" value="18"></constructor-arg>        例如2:【类型type 和  索引 index】            <constructor-arg index="0" type="java.lang.String" value="1"></constructor-arg>            <constructor-arg index="1" type="java.lang.Integer" value="2"></constructor-arg>    -->    <bean id="userId" class="com.hero.show.User" >        <constructor-arg index="0" type="java.lang.String" value="1"></constructor-arg>        <constructor-arg index="1" type="java.lang.Integer" value="2"></constructor-arg>    </bean>//---------------------------------------------------<!-- setter方法注入         * 普通数据             <property name="" value="值">            等效            <property name="">                <value>值        * 引用数据            <property name="" ref="另一个bean">            等效            <property name="">                <ref bean="另一个bean"/>    -->    <bean id="person" class="com.hero.show.Person">        <property name="pname" value="苏秦"></property>        <property name="age">            <value>1234</value>        </property>        <property name="homeAddr" ref="homeAddrId"></property>        <property name="companyAddr">            <ref bean="companyAddrId"/>        </property>    </bean>    <bean id="homeAddrId" class="com.hero.show.Address">        <property name="addr" value="江南"></property>        <property name="tel" value="911"></property>    </bean>    <bean id="companyAddrId" class="com.hero.show.Address">        <property name="addr" value="北京"></property>        <property name="tel" value="120"></property>    </bean> //--------------------------------------------------------<!--         集合的注入都是给<property>添加子标签            数组:<array>            List:<list>            Set:<set>            Map:<map> ,map存放k/v 键值对,使用<entry>描述            Properties:<props>  <prop key=""></prop>  【】        普通数据:<value>        引用数据:<ref>    -->    <bean id="collData" class="com.hero.show.CollData" >        <property name="arrayData">            <array>                <value>苏秦</value>                <value>张仪</value>                <value>孙膑</value>                <value>庞涓</value>            </array>        </property>        <property name="listData">            <list>                <value>苏秦</value>                <value>张仪</value>                <value>孙膑</value>                <value>庞涓</value>            </list>        </property>        <property name="setData">            <set>                <value>苏秦</value>                <value>张仪</value>                <value>孙膑</value>                <value>庞涓</value>            </set>        </property>        <property name="mapData">            <map>                <entry key="jack" value="杰克"></entry>                <entry>                    <key><value>rose</value></key>                    <value>肉丝</value>                </entry>            </map>        </property>        <property name="propsData">            <props>                <prop key="孔子">儒家</prop>                <prop key="老子">道家</prop>                <prop key="鬼谷子">纵横家</prop>            </props>        </property>    </bean>
2.8注解装配bean
  1. @Component取代 <bean class="">
    @Component(“id”) 取代 <bean id="" class="">
    2.web开发,提供3个@Component注解衍生注解(功能一样)取代<bean class="">
    @Repository :dao层
    @Service:service层
    @Controller:web层
    3.依赖注入 ,给私有字段设置,也可以给setter方法设置
    普通值:@Value(“”)
    引用值:
    方式1:按照【类型】注入
    @Autowired
    方式2:按照【名称】注入1
    @Autowired
    @Qualifier(“名称”)
    方式3:按照【名称】注入2
    @Resource(“名称”)
    4.生命周期
    初始化:@PostConstruct
    销毁:@PreDestroy
    5.作用域
    @Scope(“prototype”) 多例

– 组件扫描,扫描包中含有注解的类,xml添加以下配置 -

<context:component-scan
base-package="com.hero.show"></context:component-scan</beans>

注解和xml混合使用
1.将所有的bean都配置xml中

<bean id="" class="">

2.将所有的依赖都使用注解
@Autowired
默认不生效。为了生效,需要在xml配置:<context:annotation-config>

总结:
注解1:<context:component-scan base-package=" ">
注解2:<context:annotation-config>
1.一般情况两个注解不一起使用。
2. “注解1”扫描含有注解(@Component 等)类,注入注解自动生效。
“注解2”只在xml和注解(注入)混合使用时,使注入注解生效。

3.AOP

1.什么是AOP

在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP(面向对象编程)的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码.
经典应用:事务管理、性能监视、安全检查、缓存 、日志等.
Spring AOP使用纯Java实现,不需要专门的编译过程和类加载器,在运行期通过代理方式向目标类织入增强代码.
AspectJ是一个基于Java语言的AOP框架,Spring2.0开始,Spring AOP引入对Aspect的支持,AspectJ扩展了Java语言,提供了一个专门的编译器,在编译时提供横向代码的织入.

2.AOP实现原理

aop底层将采用代理机制进行实现。
接口 + 实现类 :spring采用 jdk 的动态代理Proxy。
实现类:spring 采用 cglib字节码增强实现代理。

AOP术语【掌握】
1.target:目标类,需要被代理的类。例如:UserService
2.Joinpoint(连接点):所谓连接点是指那些可能被拦截到的方法。例如:所有的方法
3.PointCut 切入点:已经被增强的连接点。例如:addUser()
4.advice 通知/增强,增强代码。例如:after、before
5. Weaving(织入):是指把增强advice应用到目标对象target来创建新的代理对象proxy的过程.
6.proxy 代理类
7. Aspect(切面): 是切入点pointcut和通知advice的结合
一个线是一个特殊的面。
一个切入点和一个通知,组成成一个特殊的面。

3.全自动代理
public interface UserService {    public void addUser();    public void updateUser();    public void deleteUser();}/** * 切面类中确定通知,需要实现不同接口,接口就是规范,从而就确定方法名称。  采用“环绕通知” MethodInterceptor.从spring容器获得目标类,如果配置aop,spring将自动生成代理。环绕通知,必须手动执行目标方法 *try{   //前置通知   //执行目标方法   //后置通知} catch(){   //抛出异常通知} */public class MyAspect implements MethodInterceptor {    @Override    public Object invoke(MethodInvocation mi) throws Throwable {        System.out.println("前");        //手动执行目标方法        Object obj = mi.proceed();        System.out.println("后");        return obj;    }}
<?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:aop="http://www.springframework.org/schema/aop"       xsi:schemaLocation="http://www.springframework.org/schema/beans                            http://www.springframework.org/schema/beans/spring-beans.xsd                           http://www.springframework.org/schema/aop                            http://www.springframework.org/schema/aop/spring-aop.xsd">    <!-- 1 创建目标类 -->    <bean id="userService" class="com.hero.aop.UserServiceImpl"></bean>    <!-- 2 创建切面类(通知) -->    <bean id="myAspect" class="com.hero.aop.MyAspect"></bean>    <!-- 3 aop编程         3.1 导包        3.2 使用 <aop:config>进行配置                proxy-target-class="true" 声明时使用cglib代理(一个代理包),写不写无所谓,只是代理的底层实现不一样,结果是一样的。            <aop:pointcut> 切入点 ,从目标对象获得具体方法            <aop:advisor> 特殊的切面,只有一个通知 和 一个切入点                advice-ref 通知引用                pointcut-ref 切入点引用        3.3 切入点表达式            execution(* com.hero.aop.*.*(..))            选择方法   第一个*表示返回值任意+包名+第二个*表示类名任意+第三个*方法名任意+(参数任意两个点..)    -->    <aop:config proxy-target-class="true">        <aop:pointcut expression="execution(* com.hero.aop.*.*(..))" id="myPointCut"/>        <aop:advisor advice-ref="myAspect" pointcut-ref="myPointCut"/>    </aop:config></beans>
public class UserServiceImpl implements UserService {    @Override    public void addUser() {        System.out.println(" addUser");    }    @Override    public void updateUser() {        System.out.println(" updateUser");    }    @Override    public void deleteUser() {        System.out.println("deleteUser");    }}//--------------------------------------------------    @Test    public void demo01(){        String xmlPath = "com/hero/show/applicationContext.xml";        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);        //获得目标类        UserService userService = (UserService) applicationContext.getBean("userService");        userService.addUser();        userService.updateUser();        userService.deleteUser();    }

输出结果:


addUser


updateUser


deleteUser

4.AspectJ

AspectJ是一个基于Java语言的AOP框架,建议使用AspectJ方式来开发AOP。

4.1切入点表达式【掌握】
1.execution() 用于描述方法 【掌握】
语法:execution(修饰符 返回值 包.类.方法名(参数) throws异常)
a.修饰符,一般省略
public 公共方法
* 任意
b.返回值,不能省略
void 返回没有值
String 返回值字符串
* 任意
c.包,可以省略
com.hero.show 固定包
com.hero.show.crm.*.service crm包下面子包任意 (例如:com.hero.show.staff.service)
com.hero.show.. crm包下面的所有子包(含自己)
com.hero.show.*.service.. crm包下面任意子包,固定目录service,service目录任意包
d.类,可以省略
UserServiceImpl 指定类
*Impl 以Impl结尾
User* 以User开头
* 任意
e.方法名,不能省略
addUser 固定方法
add* 以add开头
*Do 以Do结尾
* 任意
f.(参数)
() 无参
(int) 一个整型
(int ,int) 两个
(..) 参数任意
g.throws ,可省略,一般不写。

综合1
execution(* com.hero.show..service...*(..))
综合2:||表示两个一起匹配

<aop:pointcut expression="execution(* com.hero.*WithCommit.*(..)) ||                           execution(* com.hero.*Service.*(..))" id="myPointCut"/>
AspectJ 通知类型

Aop联盟定义通知类型,具有特性接口,必须实现,从而确定方法名称。
aspectj 通知类型,只定义类型名称。已经方法格式。
———个数:6种,知道5种,掌握around环绕通知就行。———-
before:前置通知(应用:各种校验)
在方法执行前执行,如果通知抛出异常,阻止方法运行
afterReturning:后置通知(应用:常规数据处理)
方法正常返回后执行,如果方法中抛出异常,通知无法执行
必须在方法执行后才执行,所以可以获得方法的返回值。
———————————————————–
around:环绕通知(应用:十分强大,可以做任何事情)
方法执行前后分别执行,可以阻止方法的执行
必须手动执行目标方法
———————————————————–
afterThrowing:抛出异常通知(应用:包装异常信息)
方法抛出异常后执行,如果方法没有抛出异常,无法执行
after:最终通知(应用:清理现场)
方法执行完毕后执行,无论方法中是否出现异常

基于xml实现AspectJ的AOP编程

1.目标类:接口 + 实现
2.切面类:编写多个通知,采用aspectj 通知名称任意(方法名任意)
3.aop编程,将通知应用到目标类
4.测试

/** * 切面类,含有通知 */public class MyAspect {    public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{        System.out.println("前");        //手动执行目标方法        Object obj = joinPoint.proceed();        System.out.println("后");        return obj;    }}
<!-- 1 创建目标类 -->    <bean id="userService" class="com.hero.show.UserServiceImpl"></bean>    <!-- 2 创建切面类(通知) -->    <bean id="myAspect" class="com.hero.show.MyAspect"></bean>    <!-- 3 aop编程         <aop:aspect> 将切面类 声明“切面”,从而获得通知(方法)            ref 切面类引用        <aop:pointcut> 声明一个切入点,所有的通知都可以使用。            expression 切入点表达式            id 名称,用于其它通知引用    -->    <aop:config>        <aop:aspect ref="myAspect">            <aop:pointcut expression="execution(* com.hero.show.UserServiceImpl.*(..))" id="myPointCut"/>            <!--  环绕通知                 <aop:around method="" pointcut-ref=""/>                通知方法格式:public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{                    返回值类型:Object                    方法名:任意                    参数:org.aspectj.lang.ProceedingJoinPoint                    抛出异常                执行目标方法:Object obj = joinPoint.proceed();                例如:            <aop:around method="myAround" pointcut-ref="myPointCut"/>            -->        </aop:aspect>    </aop:config>

输出结果:


addUser


updateUser


deleteUser

基于注解实现AspectJ的AOP编程
@Component@Aspect//替换 <aop:aspect ref="myAspect">public class MyAspect { //<aop:around method="myAround" pointcut-ref="myPointCut"/>    @Around(value = "myPointCut()")    public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{        System.out.println("前");        //手动执行目标方法        Object obj = joinPoint.proceed();        System.out.println("后");        return obj;    }}@Service("userServiceId")public class UserServiceImpl implements UserService {
JdbcTemplate

spring 提供用于操作JDBC工具类,类似:DBUtils。
依赖 连接池DataSource (数据源)

原创粉丝点击