spring01

马果老师整理

 

spring

  • ssh: struts2+hibernate+spring
  • ssm: spring+springmvc+mybatis

问题:什么是spring?

答:spring是一个轻量级的J2EE框架,它可以让java的企业级开发变的非常简单

问题:spring有哪些版本?

答:1.2,2.0,2.5,3.0,3.1,4.0,4.2,5.x

我们学习阶段:刚开始使用:4.2,使用maven以后版本改为4.37,在微服务架构中我们使用 5.1.6

spring提倡的一个思想,组件与组件之间尽量做到低耦合


准备工作:

在idea中,配置applicationContext.xml文件的模板




    

spring的核心概念:

IOC : 控制反转

它是一种思想,它是指创建对象、管理对象的方式,以前是自己创建自己管理,现在变成由spring容器创建,容器进行管理

DI  : 依赖注入

它是IOC的具体实现,有了spring以后,类中属性的初始化,依赖于spring容器注入的参数,才可以完成初始化,这一个
过程就称为:“依赖注入”

AOP :面向切向编程

在没有spring之间,假设:一个层次要调用另一个层次的方法(例如:Service调用Dao层的方法),可以在一个类,
自己创建另一个类的实例  

public class InfService {

	private InfDao dao;

	public void setDao(InfDao dao) {
	    this.dao = dao;
	}

	public void addData(){
	    dao.add();
	}
}

@@@@@@@:这种new对象的写法,属于一种高耦合的写法

在spring应用中,不提倡,调用者自己创建被调用者的实例,在spring的应用中,所有对象都是由spring容器来创建,
哪里,需要这个对象, spring容器就会把对象传递到哪里

-----------------------------------------------------------------------
任务1:通过spring实现hello world

步骤:

1、创建一个java工程 

2、导入jar    
spring 4.2.4
core,beans,context,expression

sprign 3.0.2
logging  (spring-framework-3.0.2.RELEASE-dependencies\org.apache.commons\com.springsource.org.apache.commons.logging\1.1.1)

3、生成spring的主配置文件  applicationContext.xml

4、创建InfDao

package org.java.dao;

public class InfDao {

    public void add(){
        System.out.println("向mysql添加了数据");
    }
}

5、在applicationContext.xml文件中,注册InfDao

6、创建InfService

public class InfService {

	private InfDao dao;

	public void setDao(InfDao dao) {
	    this.dao = dao;
	}

	public void addData(){
	    dao.add();
	}
}

7、在applicationContext.xml文件中,配置InfService,并且配置要给当前对象注入的对象


    

8、编写测试类进行测试

package org.java.demo;

import org.java.service.InfService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Demo {

    public static void main(String[] args) {

        ApplicationContext cxf = new ClassPathXmlApplicationContext("applicationContext.xml");

        InfService service = (InfService) cxf.getBean("infService");

        service.addData();
    }
}

ApplicationContext 与  applicationContext.xml是什么关系 ?

ApplicationContext:它是spring容器,它负责产生对象,只有在applicationContext.xml文件中,注册过的对象,它才能产生

问题:为什么要使用依赖注入DI

答:目的,将组件的创建与使用强制分开,降低组件与组件之间的耦合度

我们要使用某一个组件,只需要声明即可,不需要关心该组件如合创建,在运行时,spring容器会把创建好的组件
自动注入到需要它的地方

DI:它是一种组件化的思想,它可以将一个复杂应用,按功能拆分

spring应用,提倡面向接口编程:

  1. 可以隐藏实现细节
  2. 使用接口可以方便更换程序中的业务逻辑

注意:一般Service,Dao这两层都要写接口

接口的写法:

书上的规范: 

  • 接口名: org.java.dao.IDao
  • 实现类: org.java.dao.Dao

开发中的写法:

  • 接口名:  org.java.dao.InfDao
  • 实现类: org.java.dao.impl.InfDaoImpl

 


spring:按注入的数据类型,可以分为:

1、对象的注入  ref

            
                
            

2、值的注入  value

            
                
                
                
            

3、集合的注入 (List,Map,Set)        

@@@list:
            
            
                
                AAA
                BBB
                CCC
                
            
            

        @@@@Set

            
            
                
                111
                222
                333
                
            
            


        @@@@ Map

            
            
                
                one.....
                two.....
                
            
            
  • 值:value
  • 对象: ref
  • 集合:list,set,props

spring按注入的数据的方式,又可分为:

1、依赖注入

        @@@:这种方式是通过属性的set方法进行注入

           private InfDao dao;

            public void setDao(InfDao dao) {
            this.dao = dao;
            }

2、构造注入

        @@@:这种方式是通过构造方法进行注入
        需要在类中,编写一个带参数的构造方法

          public InfService(InfDao dao,String msg, int score) {
            this.dao = dao;
            }

            
            
            
            
            

3、自动绑定注入

@@@@@:这种方式注入,属性依然要生成set方法

这种写法,需要什么类型,自己在spring容器去找对应的类型,然后自己注入

  • utowire="byType"-------这种方式是按类型,自动注入,要求:匹配类型只有一个才可以使用
  • 这种方式按名称匹配,自动注入,允许有多个匹配类型

在spring应用中,为了简化开发过程,简化xml文件中的代码,spring提供了一种注解的方式

Annotations: 注释,注解

使用spring注解(spring注释)的好处:
    

  1. 代码会更为简单
  2. 简化了xml文件的代码,很多配置无需在xml文件中执行
    对象不需要在xml文件中注册
    对象之间的依赖关系,也不需要在xml文件中进行配置
  3. 对象的注入,不需要写set方法

采用spring注解的方式配置程序:

步骤:

    1、创建java工程 

    2、导入jar
        spring 4.2  
            core,beans,context,expression

            增加: aop,aspects
        
        spring 3.0.2
            logging

            增加:  aop联盟    aopalliance,
                3.0.2.RELEASE-dependencies\org.aopalliance\com.springsource.org.aopalliance\1.0.0

                   织入的包 weaver
                   3.0.2.RELEASE-dependencies\org.aspectj\com.springsource.org.aspectj.weaver\1.6.8.RELEASE

    3、编写applicationContext.xml

    4、在xml文件启用spring注解   
        

spring中的注解符号:

  •   该符号启用spring注解
  •   组件扫描,扫描org.java包下面所有加了注解标识的类

由于它是继承于

所以,只要采用组件扫描,这个标记,可以省略不写

  • 数据访问层(Dao)------------------   @Repsoitory
  • 业务逻辑层 (service)---------------  @Service
  • 控制层  (Web) ------------------  @Controller
  • 早期的用于标识组件的注解符号是: @Compoment (它可以表示:数据访问层,业务逻辑层,控制层)
@Autowired
private InfDao dao;-----------此代码,表示,按类型自动注入byType
@@@@@@@@如果采用这一种方式,注入,要求,匹配的类型,只能有一个

@Autowired
@Qualifier("dao2")
private InfDao dao; ----------此代码,表示,按照名称,自动注入 byName

在使用spring注解时,如果没有给当前组件指定别名,系统将生成,默认的别名:

生成的原则如下: 类名,首字母小写

注意:一旦给组件指定别名,默认别名就失效

 

AOP:面向切面编程(面向方面编程)

问题1:什么是aop?

答:AOP称为“面向切面编程”,也称为“面向方面编程”

问题2:aop要解决什么样的问题?

答:aop用于集中处理程序中涉及到公共性的一些辅助功能,让程序员集中精力编写业务逻辑

问题3:aop通过什么方式来实现?

答:aop主要是通过一种“通知”的形式来实现。
通知的类型有四种:它们会在不同的时候,自动的调用

  • 前置通知、后置通知、异常通知、环绕通知

问题4:通知应该如何配置?

答:要配置通知,我们要通过一种"代理模式"的方式进行配置

问题5:为什么要用代理模式?(proxy)

答:通过代理模式,可以在实现原有功能的基础上,附加额外功能

 

  •  核心任务:将程序中涉及到的公共问题,集中进行处理

将程序中,涉及到的一些辅助性的一些公共问题,集中编写成一个公共的模块,通过一定的配置,当需要这些功能的时候,
系统将会自动进行调用


AOP实现方式,主要是通过一种"通知"的方式进行实现 (Advice)

spring的AOP提供了四种类型的通知,分别在不同的时候自动运行:

  1. 前置通知--------------------配置在前置通知的代码,将会在业务逻辑执行之前自动调用 
  2. 后置通知--------------------配置在后置通知的代码,将会在业务逻辑执行之后自动调用 
  3. 异常通知--------------------配置在异常通知的代码,将会在业务逻辑执行过程中,产生异常时执行
  4. 环绕通知--------------------它把整个业务逻辑执行过程包含在通知中

@@@@@@@@@如何配置通知
    在AOP中,配置通知,需要使用一种设计模式:代理模式(proxy)

代理模式:通过代理可以在实现原有功能的基础上,附加额外功能

@@@@@@@:使用代理模式的目的,要在原有功能的基础上,附加额外功能

示例:

applicationContext.xml

    
    

    
    
    

    
    
        
        
            org.java.service.BuyBookService
        
        
        
            
                before
                after
            
        
        
        
    

AfterAdvice.java

package org.java.advice;

import org.springframework.aop.AfterReturningAdvice;

import java.lang.reflect.Method;

public class AfterAdvice implements AfterReturningAdvice {

    @Override
    public void afterReturning(Object returnValue, Method method, Object[] objects, Object o1) throws Throwable {
        System.out.println("");
        System.out.println("------后置通知----------");
    }
}

BeforeAdvice.java

package org.java.advice;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * 前置通知,此处的代码,在执行业务逻辑代码之前,自动运行
 */
public class BeforeAdvice implements MethodBeforeAdvice {

    /**
     *
     * @param method:即将执行的是类中的哪一个业务方法
     * @param objects:调用方法时,要传递给方法的参数有哪些
     * @param o:即将要执行的是哪一个业务逻辑类
     * @throws Throwable
     */
    @Override
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println("-------进入前置通知类-------------");
        System.out.println("即将访问的业务类是:"+o.getClass());
        System.out.println("即将访问的业务方法是:"+method.getName());
        System.out.println("即将传递给方法的参数有:"+ Arrays.toString(objects));
        System.out.println("-------离开前置通知类-------------");

        System.out.println("");
    }
}

BuyBookServiceImpl.java

package org.java.service.impl;

import org.java.service.BuyBookService;

/**
 * 业务实现类
 */
public class BuyBookServiceImpl implements BuyBookService {

    @Override
    public String buyBook(String who, String bookName) {
        System.out.println("-----------------进入业务逻辑类------------------");

        System.out.println("正在进行业务逻辑处理");

        System.out.println("-----------------离开业务逻辑类------------------");
        return who+",购买了书:"+bookName;
    }
}

测试

package org.java.demo;

import org.java.service.BuyBookService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Demo {

    public static void main(String[] args) {

        ApplicationContext cxf = new ClassPathXmlApplicationContext("applicationContext.xml");

        BuyBookService service = (BuyBookService) cxf.getBean("proxy");

        service.buyBook("张三","环球地理");
    }
}

 

前置通知:它会在业务逻辑类调用之前先执行,前置通知需要实现接口: MethodBeforeAdvice

后置通知:它会在业务逻辑类调用之后执行,后置通知,需要实现接口:AfterReturningAdvice

异常通知:它会在业务逻辑类执行过程中,如果产生了异常才会被调用,异常通知,需要实现接口ThrowsAdvice

异常通知中,没有强制实现的方法,但我们写的方法要满足以下规则:

    public void afterThrowing(Method method,Object[] args,Object target,Exception ex ){
    
    }

环绕通知:它把整个业务逻辑类的执行包含在通知里面,环绕通知,一般实现:MethodInterceptor


目前,这一种代理方式存在的问题:

  • 问题1: 针对于每一个业务类配置一个代理,如果有1000个业务类,就需要配置1000个代理类
  • 问题2: 这种方式配置代理,每一次都需要访问代理类的名称,才能有附加功能

解决方案1:

采用自动代理

优点:

  1. 代理由系统根据访问的业务的名称,自动创建代理
  2. 直接访问业务类的名称即可,不用访问代理类的名称
        
        
        
            
            before
            after
            mythrows
            
        
        
        
            
            buyBookService
            service2
            service3
            
        
        

解决方案2:

声明式代理

优点:

  1. 对某一个包路径下面的所有业务类,形成代理(无需修改代码)
  2. 直接访问业务类的名称即可,不用访问代理类的名称
  3. 采用声明式代理,通知写在一个类中即可,这个类,无需实现任何接口 
    
        
        
        
        
        
            
            
            
            
        
        

解决方案3:采用注解的方式配置


        
        

        
        

        @Before(value = "execution(* org.java.service.*.*(..))")
        public void before(JoinPoint jp){
            System.out.println("------------------------进入前置通知");
        }


 

 

你可能感兴趣的:(Spring)