java初入之spring框架


Spring是一个轻量级控制反转(IoC)和面向切面(AOP)的容器框架
控制反转:类的实例和生命周期的管理交由外部容器(spring)来实现;

轻量级、重量级的定义:
  一个框架的轻重量级,是由该框架启动的服务来定义的,启动的服务多,对应用的性能消耗就会多,就属于重量级的框架,反之就是轻量级的框架;

spring的配置文件(获取spring对象时需要此配置文件)
  Spring 的引入,下载jar包或者在xml文件中注入;

Spring的使用之配置文件:
  <?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-2.5.xsd">
  </beans>

在xml文件的bean容器中将类交给spring管理
  ForE: <bean id = "xxxInterface" class="packagePath"+".className" scope=""></bean>

  id:通过spring容器获得类的实例时候的标识;
  class : 要实例的类;
  scope : 类的作用范围,singleton ,单例模式,一个Spring的容器中只存在一个类的实例;
  propotype ,每次请求都会返回一个新的实例

在xml文件中在一个类中注入另一个类的引用
  ForE:<bean id="secondinterface" class="impl.SecondInterfaceImpl">
  <constructor-arg index="0" ref="firstinterface"/>
  </bean>
  <bean id="firstinterface" class="impl.FirstInterfaceImpl"></bean>
方法一:通过构造函数注入
  SecondInterfaceImpl(FirstInterface mFirstInterface){
  this.mFirstInterface=mFirstInterface;
  }
如果做了上面的配置,Spring在实例化SecondInterface的时候,会将FirstInterface的实例注入到构造方法中
方法二:通过set方法注入
  <bean id="secondinterface" class="impl.SecondInterfaceImpl">
    <property name="mFirstInterce" ref="firstinterface"/>
  </bean>
  <bean id="firstinterface" class="impl.FirstInterfaceImpl"></bean>

在SecondInterface中声明FirstInterface的set方法
  public void setmFirstInterface(FirstInterface mFirstInterface) {
  this.mFirstInterface = mFirstInterface;
  }

同样可以将FirstInterface的实例注入到SecondInterface中

bean的生命周期方法 
  (init-method、destroy-method)
  <bean id="firstinterface" class="impl.FirstInterfaceImpl" init-method="init" destroy-method="stop"></bean>

这样配置之后,通过ClassPathApplicationContext调用getBean()实例化类的时候,会首先调用FirstInterface的init()方法,同事调用destroy()方法之前会调用FirstInterface的stop方法

全局配置(default-init-method/default-destroy-method)
  <beans
  ...
  default-init-method="init"
  default-destroy-method="destroy"
  ></beans>
这样声明之后,beans下所有的bean声明的类都会调用各自的init和destroy方法

继承InitializingBean/DisposableBean接口
如果类继承了InitializingBean接口,会重写afterPropetiesSet()方法,此方法会在spring实例化类之前调用
如果继承了DisposableBean接口,会复写destroy()方法,此方法会在spring调用自己的destroy之前调用;

优先级 实现接口>init-method/destroy-method>default-init-method/default-destroy-method


XXXAware接口
Spring提供了以Aware为结尾的一系列接口,方便我们可以拿到spring的一些资源
ForE:
  ApplicationContextAware接口,实现此接口会复写setApplicationContext(ApplicationContext context)方法,此方法可以拿到spring的上下文
  BeanNameAware 接口,实现此接口会复写setBeanName(String str)方法,str表示的xml文件中配置的bean的id(注:谁实现的此接口,name就表示谁的id)

总的来说,感觉没啥用,自己配的难道不知道么,0_0!!!!


自动装配
  所谓的自动注入,就是通过配置属性的方法,有Spring在配置文件中寻找相应的类进行注入,不需要通过在bean中配置propoty或是constructor-arg;

  1)<beans
  ...
  default-autoware="byName"
  ></beans>

此配置会根据要实现注入的类中成员的名称为标准,一一比对xml文件中的id属性,有相同的就会将实例注入
如SecondInterface 中有一个成员
  public FirstInterface mFirstInterface;
  public void SetFirstInterface(FirstInterface mFirstInterce){}
    <bean id="secondinterface" class="...SecondInterfaceImpl">
    <bean id="mFirstInterface" class="...FirstInterfaceImpl">

这样就可以实现将FirstInterface的实例注入到SecondInterface中,注意成员变量名和id的名称要一致;

2)<beans
...
default-autoware="byType"
></beans>

实现方法和byName一致,不过set()方法要注入的实例是根据class属性来查找的

3)<beans
...
default-autoware="constructor"
></beans>

通过构造器注入,顾名思义,根据构造方法实现的注入,构造方法要注入的实例也是根据class属性来查找的;


Resource
  ApplicationContext 实现了ResourceLoader接口,因此可以调用getResource(String path)方法,读取一些资源文件(ApplicationContext可以实现    ApplicationContextAware接口获得)

  getResource("classpath*:"+xxx)
  getResource("file:"+绝对路径(ForE D:\xxx\xxx));
  getResource("url:"+网络路径)
  getResource(xxx),这样写默认的是与ApplicationContext的创建方式一样的(new ClassPathApplicationContext("classpath*:"+xxx)),这样默认的也是根据classpath来的


注解篇:

要是用注解,首先需要在xml文件中进行配置
  <beans
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd"
  >
  <context:component-scan base-package="packageName"/>
  </beans>

这样配置之后Spring会扫描packageName包下的类,查看其是否有注解,有就进行管理
配置文件:xsi:schemaLocation 配置的路径是与命名空间对应的schema文件装载路径

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

上面三个注解都是将类交给Spring进行管理,与在xml中申明bean效果是一样的,没个注解都有name属性,类似xml的id属性

  @scope("prototype/singleton")申明类的实例类型,单例还是工厂

针对类中
  @Required 用于setter方法,此注解表示的方法,注入的对象不能为空,否则会抛异常
  @Autowired(和@Inject等价) 用于set方法,成员变量和构造器,此注解标注的方法,注入的对象默认不能为空,为空抛异常,要想不抛异常,使用                 @Autowired(requred=false)
注意:使用@Autowired时,每个类只能有一个构造器标注为requred=true,不过Requred=true时,建议使用Requred惊醒注解;

  @PostConstruct 在类初始之前执行某个方法 @PreDestroy 在类销毁前执行某个方法;



AOP(Aspect Oriented Programming)面向切面编程
  AOP的两种实现方式:预编译和运行期动态代理
    概念
    切面:贯穿多个业务功能(体现在代码中就是多个业务类)关注点;
    连接点(Joinpoint):程序执行过程中的某一步;
    通知:(在连接点上进行的操作)
    前置通知:连接点代码执行前进行的操作,不能阻止连接点的执行,除非抛异常
    异常通知:连接点代码运行异常后执行的操作
    返回后通知:连接点代码顺利执行完毕后进行的操作
    后通知:连接点代码执行后的操作,不管顺利执行还是抛异常
    环绕通知:包围一个连接点的通知
    切入点:匹配到的连接点
    引入(Introduction):再不修改代码的前提下添加新的属性或方法
    目标对象:通知的对象
    AOP代理:AOP框架创建的对象
    织入(Weaving):把切面关联到业务功能的对象或者业务类上,并创建一个目标对象,分为编译时织入,类加载时织入和执行时织入

AOP配置之xml篇
  <bean id="aspectClass" class = "xxx"/>
  <bean id="pointCutClass" class = "xxx"/>
  <aop-config>
    <aop-aspect id="myAOPAspect" ref="aspectClass">
      <aop:pointcut expression="execution(*impl.FirstInterface*(..))" id="myPointCut">
      <aop:before method="before" pointcut-ref="myPointCut">
      <aop:after-returning method="afterReturn" pointcut-ref="myPointCut">
      <aop:after-throwing method="afterThrowing" pointcut-ref="myPointCut">
      <aop:after method="After" pointcut-ref="myPointCut">
    </aop-aspect>
  </aop-config>


  aop-aspect ref 指定的是切面(类),aop:before/after等指定的方法都必须在此类中存在
  aop:pointcut expression属性制定的是切点格式execution(* packageName.className.MethodName||*(..))后一种方法表示所有的方法都会执行拦截通知

  循环通知:aop-around
  
  aop-around 制定的方法,必须有一个参数(且必须是第一个)ProceedingJoinPoint,这个参数有一个方法proceed(),调用这个方法,就会执行切入点的方法的代码,因此,可以在业务代码执行前后进行一些操作;

  ForE: <aop-around method="aroundMethod" pointcut-ref="..."/>
      public void aroundMethod(ProceedingJoinPoint joinPoint,String name,int age){
        Syso.("业务代码执行前");
        joinPoint.proceed();
        Syso.("业务代码执行后");
      }

业务代码方法的参数,可以通过在环绕通知方法后面追加同类型的参数传递过来


Introduction:让制定的类,强制实现一个接口(强制给他一个爸爸)
ForE:
  <aop:declare-parents 
    types-matching="impl.*(+)"
    implement-interface="impl.xxxInterface"
  default-impl="impl.xxxInterfaceImpl"/>
这样申明之后,所有的impl包下的类都会实现xxxInterface接口,xxxInterface有一个默认的实现类xxxInterfaceImpl,避免调用接口方法时异常;

posted on 2017-04-10 11:42  秦家十月  阅读(108)  评论(0)    收藏  举报

导航