码迷,mamicode.com
首页 > 编程语言 > 详细

spring总结

时间:2015-04-19 11:22:48      阅读:144      评论:0      收藏:0      [点我收藏+]

标签:

Spring介绍

Spring是一个非常活跃的开源框架;它是一个基于IOC和AOP来构架多层JavaEE系统的框架,它的主要目地是简化企业开发.

  Spring以一种非侵入式的方式来管理你的代码,Spring提倡”最少侵入”,这也就意味着你可以适当的时候安装或卸载Spring

  官网:http://www.springsource.org/

(1)应用Spring的好处

l  方便解耦,简化开发

  • Spring就是一个大工厂,可以将所有对象创建和依赖关系维护,交给Spring管理

l  AOP编程的支持

  • Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能

l  声明式事务的支持

  • 只需要通过配置就可以完成对事务的管理,而无需手动编程

l  方便程序的测试

  • Spring对Junit4支持,可以通过注解方便的测试Spring程序

l  方便集成各种优秀框架

  • Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts、Hibernate、MyBatis、Quartz等)的直接支持

l  降低JavaEE API的使用难度

  • Spring 对JavaEE开发中非常难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大降低

(2)Spring模块介绍

Spring 框架是一个分层架构,,它包含一系列的功能要素并被分为大约20个模块。这些模块分为Core Container、Data Access/Integration、Web、AOP(Aspect Oriented Programming)、Instrumentation和测试部分,如下图所示:

技术分享

功能(一) IOC  控制反转

分为两部分

【IOC】

IOC就是 Inversion of Control

所谓控制反转就是应用本身不负责依赖对象的创建及维护,依赖对象的创建及维护是由外部容器负责的。这样控制权就由应用转移到了外部容器,控制权的转移就是所谓反转,目的是为了获得更好的扩展性和良好的可维护性。

【DI】

Dependency Injection

所谓依赖注入就是指:在运行期,由外部容器动态地将依赖对象注入到组件中。

a: 配置(IOC、DI)

到http://www.springsource.org/download下载spring,然后进行解压缩,在解压目录中找到下面jar文件,拷贝到类路径下

   * org.springframework.beans-3.2.0.RELEASE.jar

      所有应用都要用到的,它包含访问配置文件、创建和管理bean

      以及进行Inversion of Control / Dependency Injection(IoC/DI)操作相关的所有类

    * org.springframework.context-3.2.0.RELEASE.jar

      Spring提供在基础IoC功能上的扩展服务,此外还提供许多企业级服务的支持,

      如邮件服务、任务调度、JNDI定位、EJB集成、远程访问、缓存以及各种视图层框架的封装等。

    * org.springframework.core-3.2.0.RELEASE.jar

      包含Spring框架基本的核心工具类,Spring其它组件要都要使用到这个包里的类,是其它组件的基本核心。

    * org.springframework.expression-3.2.0.RELEASE.jar

      Spring表达式语言

    * org.apache.commons.logging-1.1.1.jar(spring-framework-3.0.2.RELEASE-dependencies)

      第三方的主要用于处理日志

提示:spring3.0.X 版本 asm jar包 已经被合并到 spring core包中

创建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.xsd“>

</beans>

该配置模版可以从spring的参考手册或spring的例子中得到。配置文件的取名可以任意,文件可以存放在任何目录下,但考虑到通用性,一般放在类路径下。

在spring的配置文件中增加如下配置 –ioc

<bean id="boy" class="cn.itcast.ioc.Boy"></bean>

bean节点中Id和name的区别:

如果spring当前版本是3.0的时候,id和name有以下区别

如果spring当前版本是3.2的时候,id和name的属性可以通用

Spring3.0区别一:

id:指定唯一实例引用

name:可以指定多个实例引用,例如name=“boy,boy1”

Spring3.0区别二:

id :id的命名要满足XML对ID属性命名规范

      例如:必须以字母开始,可以使用字母、数字、连字符、下划线、句话、冒号

name:如果Bean的名称中含有特殊字符,就需要使用name属性

      例如:<bean name="# boy " class="cn.itcast.ioc.Boy"/>

在spring的beans.xml文件中增加如下配置,红色的为新增加的—di

<bean id="boy" class="cn.itcast.di.Boy"></bean>

 

 <!-- 创建girl的对象 -->

 <bean id="girl" class="cn.itcast.di.Girl">

   <!-- 依赖注入 把boy对象传递给girl   property name="boy1"使用 public void

        setBoy1(Boy boy1)   à

   <property name="boy">

       <!-- 引用 bean id="boy"中的boy -->

       <ref bean="boy"/>

   </property>

 </bean>

实例化spring容器的方式

方法一:

在类路径下寻找配置文件来实例化容器

ApplicationContext ctx = new ClassPathXmlApplicationContext(new String[]{"beans.xml"});

可以在整个类路径中寻找xml文件

     * 通过这种方式加载。需要将spring的配置文件放到当前项目的classpath路径下

     *  classpath路径指的是当前项目的src目录,该目录是java源文件的存放位置。

方法二:

在文件系统路径下寻找配置文件来实例化容器

ApplicationContext ctx = new FileSystemXmlApplicationContext(new String[]{“d:\\beans.xml“});

Spring的配置文件可以指定多个,可以通过String数组传入。

BeanFactory和ApplicationContext

技术分享

当使用spring时,我们可以使用容器提供的众多服务

技术分享

b.三种实例化bean的方式

1.使用类构造器实例化(默认无参数)

<bean id=“personService" class="cn.itcast.bean.impl.PersonServiceImpl"/>

2.使用静态工厂方法实例化(简单工厂模式)

<bean id="personService"

        class="com.itcast.factory.PersonServiceFactory"    factory-method="createPersonService" />

public class PersonServiceFactory {

      public  static PersonService createPersonService(){

                return new PersonServiceImpl();

      }

}

3.使用实例工厂方法实例化(工厂方法模式):

 <bean id=“personServiceFactory" class="com.itcast.factory.PersonServiceFactory"/>

 <bean id="personService" factory-bean=“personServiceFactory"

                                                                         factory-method="createPersonService" />

public class PersonServiceFactory {

       public  PersonService createPersonService(){

                     return new PersonServiceImpl();

       }

Bean的作用域

* singleton(默认值)

     在每个Spring IoC容器中一个bean定义只有一个对象实例(共享)。

      默认情况下会在容器启动时初始化bean,但我们可以指定Bean节点的lazy-init=“true”来延迟初始化bean,这时候,只有第一次获取bean会才初始化bean。如:

 <bean id="xxx" class="cn.itcast.OrderServiceBean" lazy-init="true"/>

    如果想对所有bean都应用延迟初始化,可以在根节点beans设置default-lazy-init=“true“,如下:

<beans default-lazy-init="true“ ...>

* prototype

      允许bean可以被多次实例化(使用一次就创建一个实例)

* request每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境(一个系统request.setAttribute () )

* session同一个HTTP Session 共享一个Bean,不同Session使用不同Bean,仅适用于WebApplicationContext 环境(一个系统session.setAttribute())

* global session一般用于Porlet应用环境,该作用域仅适用于WebApplicationContext 环境(多个系统共享一个session)

Bean的生命周期

  1. instantiate bean对象实例化
  2. populate properties 封装属性
  3. 如果Bean实现BeanNameAware 执行 setBeanName
  4. 如果Bean实现BeanFactoryAware      或者      ApplicationContextAware 设置工厂      setBeanFactory 或者上下文对象 setApplicationContext     
  5. 如果存在类实现      BeanPostProcessor(后处理Bean) ,执行如果Bean实现InitializingBean      执行      afterPropertiesSet
         接口      BeanPostProcessor 后处理Bean 提供两个钩子函数,用于开发者      动态去修改Bean对象  (动态代理)
  6. 如果bean实现InitializingBean,执行afterPropertiesSet()初始化
  7. 调用<bean init-method=“userInitMethod"> 指定初始化方法 userInitMethod
  8. 如果存在类实现      BeanPostProcessor(处理Bean) ,执行postProcessAfterInitialization
  9. 执行业务处理,即用户自定义的业务操作
  10. 如果Bean实现 DisposableBean      执行      destroy
  11. 调用<bean destroy-method=“userDestroyMethod"> 指定销毁方法      userDestroyMethod

依赖注入

手工装配

       * 使用xml配置文件

               *  使用属性setter方法注入  1.1

               *  使用构造器注入          1.2

       * 使用注解

              * autowired注解                   2.1

              * resource注解                    2.2

 * 自动装配                                    2.3

       * byType按类型装配

       * byName:按名称装配

       * constructor装配

       * autodetect 不确定装配。

注入依赖对象可以采用手工装配或自动装配,在实际应用中建议使用手工装配,因为自动装配会产生未知情况,开发人员无法预见最终的装配结果。

依赖注入

1.1使用属性setter方法注入

通过setter方法注入依赖

<bean>元素的< property >子元素指明了使用它们的set方法来注入。可以注入任何东西,从基本类型到集合类,甚至是应用系统的bean。

【1】简单bean配置

配置bean的简单属性,基本数据类型和String。

<bean id="personService"   class="com.itcast.bean.impl.PersonServiceImpl">

               <!-- 基本类型,string类型 -->

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

              <property name="name" value="张无忌"></property>                       

</bean>

【2】引用其它bean(外部bean)

<bean id="person" class="com.itcast.bean.Person" />

       <bean id="personService"  class="com.itcast.bean.impl.PersonServiceImpl">

       <!-- 引用类型 -->

       <property name="person" ref="person" />

</bean>

【3】引用其它bean内部bean

<bean id="personService" class="com.itcast.bean.impl.PersonServiceImpl">

          <!-- 内部bean注入 -->

         <property name="personClass">

             <bean class="com.itcast.bean.PersonClass" />

         </propert>

</bean>

这种方式的缺点是你无法在其它地方重用这个personClass实例,原因是它是专门为personService而用。

 

 

【4】使用p命名空间

为了简化XML文件配置,Spring从2.5开始引入一个新的p名称空间

p:<属性名>="xxx" 引入常量值

p:<属性名>_ref="xxx" 引用其它Bean对象

技术分享

【5】装配集合List和数组

若bean的属性是集合类型,按如下处理:

<!-- 装配list -->

<property name="lists">

       <list>

           <value>list1</value>

           <value>list2</value>

           <ref bean="person"/>

       </list>

</property>

 

<!-- 装配数组 -->

<property name="obj">

   <array>

       <value>obj1</value>

       <value>obj2</value>

       <ref bean="person"/>

   </array>

</property>

【6】装配set

<!-- 装配set -->

<property name="sets">

     <set>

         <value>set1</value>

         <value>set2</value>

         <ref bean="person"/>

     </set>

</property>

set使用方法和list一样,不同的是对象被装配到set中,而list是装配到List或数组中装配。

 

【7】装配map:

<!-- 装配map-->

<property name="maps">

             <map>

                  <entry key="01">

                          <value>map01</value>

                  </entry>

                  <entry key="02">

                          <value>map02</value>

                  </entry>

             </map>

</property>

简化为:

<property name="maps">

             <map>

                  <entry key="01" value="map01"></entry>

                  <entry key="02" value="map02"></entry>

             </map>

</property>

map中的<entry>的数值和<list>以及<set>的一样,可以使任何有效的属性元素,需要注意的是key值必须是String的。

【8】装配集合Property

<!--装配Properties  -->

<property name="props">

           <props>

             <prop key="01">prop1</prop>

             <prop key="02">prop2</prop>

           </props>

</property>

【9】装配集合List(null)

<!-- 装配null -->

<property name="listnull">

         <null/>

</property>

1.2使用构造器注入         

【1】通过参数的顺序:

<constructor-arg index="0">

      <value>张三</value>

</constructor-arg>

<constructor-arg index="1">

       <value>56</value>

 </constructor-arg>

 

【2】通过参数的类型:

<!-- 通过参数的类型 -->

<constructor-arg type="java.lang.Integer">

       <value>56</value>

</constructor-arg>

<constructor-arg type="java.lang.String">

       <value>张三</value>

</constructor-arg>

2.1  autowired注解                  

在java代码中使用@Autowired或@Resource注解方式进行装配的前提条件是。

【1】引入context命名空间  需要在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-3.0.xsd

           http://www.springframework.org/schema/context

           http://www.springframework.org/schema/context/spring-context-3.0.xsd">

       <context:annotation-config/>

  </beans>

 

【2】在配置文件中添加context:annotation-config标签

      <context:annotation-config/>

这个配置隐式注册了多个对注解进行解析处理的处理器

AutowiredAnnotationBeanPostProcessor,CommonAnnotationBeanPostProcessor,

PersistenceAnnotationBeanPostProcessor,RequiredAnnotationBeanPostProcessor

注: @Resource注解在spring安装目录的

spring-framework-3.0.2.RELEASE-dependencies\javax.annotation\com.springsource.javax.annotation\1.0.0包下com.springsource.javax.annotation-1.0.0.jar

         但是这里:

如果使用jdk1.5,需要引入com.springsource.javax.annotation-1.0.0.jar

       如果使用jdk1.6,不需要引入com.springsource.javax.annotation-1.0.0.jar

 

【3】使用注解@autowired标注在属性上

Autowired标注在字段上     

     *  @Autowired注解默认按类型进行装配

     *  获取该注解标注的字段的类型---PersonDao类型

     *  以该类型为条件到spring容器(beans.xml)中去查找bean的id节点的类型是PersonDao类型.

     *  找到以后,获取该节点对应的对象,利用反射直接为personDao变量赋值

@Qualifier(“personDao”)该注解以名字为条件查找依赖对象

     *  以该注解的的参数personDao条件到spring容器(beans.xml)中去查找bean的id节点的值是personDao的对象

     *  找到以后,获取该节点对应的对象, 利用反射直接为personDao变量赋值,如果不存在该名称,抛出异常

例如:

技术分享

 

【4】使用注解@autowired标注在set方法上

Autowired标注在setter方法上          

     @Autowired注解默认按类型进行装配

      *  获取 setPersonDao()方法的参数的类型---PersonDao类型

      *  以该类型为条件到spring容器(beans.xml)中去查找bean的id节点的类型是PersonDao类型.

           * 找到以后,获取该节点对应的对象, 把该对象作为实参传递给该setPersonDao(

PersonDao personDao)的形参.

@Qualifier("personDao")该注解以名字为条件查找依赖对象

           *  以该注解的的参数personDao条件到spring容器(beans.xml)中去查找bean的id节点的值是PersonDao的对象

           *  找到以后,获取该节点对应的对象, 把该对象作为实参传递给该setPersonDao(

PersonDao personDao)的形参.

           * 如果不存在该名称,抛出异常

例如:

技术分享

 2.2  resource注解                   

1】使用注解@Resource标注在属性上

Resource注解标注在字段上       

    * @Resource注解默认按名称装配。

    * 如果没有指定name属性

         *  获取该注解标注的字段值---personDao

              *  以该字段值为条件到spring容器(beans.xml)中去查找bean的id节点的值是 personDao的节点

              * 找到以后,获取该节点对应的对象, 利用反射直接为personDao变量赋值

              * 如果没有找到.并且按照默认的名称找不到依赖对象时, @Resource注解会回退到按类型装配

              * 获取该注解标注的字段类型--PersonDao

              * 以该类型为条件到spring容器(beans.xml)中去查找bean的节点的类型是PersonDao类型的对象

              * 找到以后,获取该节点对应的对象,利用反射直接为personDao变量赋值

   * 如果指定name属性,只能按名称装配

              *  获取name属性的值 personDao

              *  以该值为条件到spring容器(beans.xml)中去查找bean的id节点的值是PersonDao的对象

              * 找到以后,获取该节点对应的对象, 利用反射直接为personDao变量赋值

              * 如果不存在该名称,抛出异常

例如:

技术分享

【2】使用@Value注解装配值

@Value注解

在UserServiceImpl的类中定义

@Value(value="金毛狮王")

private String name;

@Value(value="50")

private Integer age;

注意:这里可以省略set()方法

相当于spring容器中配置:

技术分享

【3】使用注解@Resource标注在set方法上

resource注解标注在setter方法上    

   *  @Resource注解默认按名称装配。

   *  如果没有指定name属性

        *  获取setPersonDao()方法的属性名---personDao

             *  以该属性名为条件到spring容器(beans.xml)中去查找bean的id节点的值是personDao的节点

             * 找到以后,获取该节点对应的对象, 把该对象作为实参传递给该setPersonDao(

PersonDao personDao)的形参.

             *  如果没有找到.并且按照默认的名称找不到依赖对象时,@Resource注解会回退到按类型装配

             *  获取setPersonDao()方法的参数类型---PersonDao

             *  以该类型为条件到spring容器(beans.xml)中去查找bean的节点的类型是PersonDao类型对象

             *  找到以后,获取该节点对应的对象, 把该对象作为实参传递给该setPersonDao(

PersonDao personDao)方法的形参       

   * 如果指定name属性  只能按名称装配

             *  获取name属性的值

             *  以该值为条件到spring容器(beans.xml)中去查找bean的id节点的值是PersonDao的对象

             * 找到以后,获取该节点对应的对象, 把该对象作为实参传递给该setPersonDao(

PersonDao personDao)的形参.

             * 如果不存在该名称,抛出异常

例如:

技术分享

3.1)手工装配:bean之间的关系(了解知识)

【1】继承

继承,如果多个Bean具有相同的方法和属性,则可以引入父类Bean,配置父子bean关系

技术分享

【2】依赖

依赖,一个类内部运行依赖另一个Bean初始化一些数据

SystemInfo 会对 SystemInfo的 taskPeroid 任务周期进行初始化

TaskManager 需要使用 SystemInfo提供  taskPeroid 指定任务周期

总结:TaskManager 依赖 SystemInfo 初始化数据 依赖关系Bean,必须先初始化 SystemInfo 后初始化 TaskManager

(4)手工装配,配置多个XML文件(spring容器)

使用多个XML配置文件

方式一 可以在创建ApplicationContext对象时传入多个配置文件

         ApplicationContext applicationContext = new

         ClassPathXmlApplicationContext("beans1.xml", "beans2.xml");

 

方式二 可以在配置文件中通过<import>引入其他配置文件

         <import resource="classpath:bean2.xml"/>

 

我们再开发中,一般使用第二种方式加载多个XML文件:例如:

在:src的beans.xml中添加:

<import resource="classpath:cn/itcast/beans.xml"/>

技术分享

【3】引用

引用,一个Bean可以将另一个Bean的id注入到程序中,在运行期获得其实例

技术分享

classpath自动扫描把组件纳入spring容器中管理

       <context:component-scan base-package="cn.itcast"/>

       其中base-package为需要扫描的包(含子包)。

:

1、在使用组件扫描元素时,AutowiredAnnotationBeanPostProcessor 和CommonAnnotationBeanPostProcessor会隐式地被包括进来。 也就是说,每个组件都会被自动检测织入 - 所有这一切都不需要在XML中提供任何bean配置元数据。

2、功能介绍

@Service用于标注业务层组件、

@Controller用于标注控制层组件(如struts中的action)、

@Repository用于标注数据访问组件,即DAO组件。

而@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。

3.2手工装配,配置多个XML文件(spring容器)

使用多个XML配置文件

方式一 可以在创建ApplicationContext对象时传入多个配置文件

         ApplicationContext applicationContext = new

         ClassPathXmlApplicationContext("beans1.xml", "beans2.xml");

 

方式二 可以在配置文件中通过<import>引入其他配置文件

         <import resource="classpath:bean2.xml"/>

 

我们再开发中,一般使用第二种方式加载多个XML文件:例如:

在:src的beans.xml中添加:

<import resource="classpath:cn/itcast/beans.xml"/>

功能(二)AOP  面向切面编程

1 :AOP代理模式

代理模式:代理模式的英文叫做Proxy或Surrogate,中文都可译为”代理“,所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动。在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用

 

抽象主题角色声明了真实主题和代理主题的共同接口,这样一来在任何可以使用真实主题的地方都可以是使用代理主题

 

代理主题(Proxy)角色:代理主题角色内部含有对真实主题的引用,从而可以在任何时候操作真实主题对象;代理主题角色提供一个与真实主题角色相同的接口,以便可以在任何时候都可以替代真实主题控制对真实主题的引用,负责在需要的时候创建真实主题对象(和删除真实主题对象);代理角色通常在将客户端调用传递给真实的主题之前或之后,都要执行某个操作,而不是单纯地将调用传递给真实主题对象。

 

真实主题角色:定义了代理角色所代表地真实对象

 技术分享

2:JDK动态代理

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.lang.reflect.Proxy;

public class JDKProxy implements InvocationHandler{

private Object targerObject;//代理的目标对象

    /**

     * 创建代理对象

     * @param targerObject 目标对象

     * @return

     */

public Object createProxyInstance(Object targerObject){

     this.targerObject=targerObject; 

     /*

      * 第一个参数设置代码使用的类加载器,一般采用跟目标类相同的类加载器

      * 第二个参数设置代理类实现的接口,跟目标类使用相同的接口

      * 第三个参数设置回调对象,当代理对象的方法被调用时,会调用该参数指定对象的invoke方法

      */

     return Proxy.newProxyInstance(

                   targerObject.getClass().getClassLoader(),

                   targerObject.getClass().getInterfaces(),

                   this);

     }

/**

     * @param proxy   目标对象的代理类实例

     * @param method  对应于在代理实例上调用接口方法的Method实例

     * @param args 传入到代理实例上方法参数值的对象数组

     * @return 方法的返回值 没有返回值时是null

     */

  public Object invoke(Object proxy, Method method, Object[] args)

       throws Throwable {

      System.out.println("代理类实例 "+proxy.getClass());

      System.out.println("方法名称 "+method.getName());

      if(args!=null&&args.length>0){//方法的参数值

           for(int i=0;i<args.length;i++){

                System.out.println("方法参数值 "+args[i].toString()); }

          }

          Object returnvalue=null; //定义方法的返回值 没有返回值时是null

          returnvalue=method.invoke(this.targerObject, args); //调用目标对象的方法

          System.out.println("方法的返回值 "+returnvalue);

           return returnvalue;

      }

}

 

3:CGLIB代理

CGlib是一个强大的,高性能,高质量的Code生成类库。它可以在运行期扩展Java类与实现Java接口。

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;

import net.sf.cglib.proxy.MethodInterceptor;

import net.sf.cglib.proxy.MethodProxy;

 

public class UserManagerCglibProxy implements MethodInterceptor {

    private Object targerObject;  //代理的目标对象

 /**

     * 创建目标对象的代理对象

     * @param targerObject 目标对象

     * @return

     */

    public Object createProxyInstance(Object targerObject){

          this.targerObject=targerObject;

          Enhancer enhancer=new Enhancer();   //该类用于生成代理对象

         enhancer.setSuperclass(this.targerObject.getClass());  //设置父类

         enhancer.setCallback(this);  //设置回调用对象为本身

        return enhancer.create();    //创建代理对象

   }

    /**

    * @param obj  目标对象代理类的实例

    * @param method 代理实例上调用父类方法的Method实例

    * @param args  传入到代理实例上方法参数值的对象数组

    * @param methodProxy 使用它调用父类的方法

    * @return

    * @throws Throwable

    */

public Object intercept(Object obj, Method method, Object[] args,

                                            MethodProxy methodProxy) throws Throwable {

           System.out.println("代理类 "+obj.getClass());

           System.out.println("方法名称 "+method.getName());

           if(args!=null&&args.length>0){//方法的参数值

                 for(int i=0;i<args.length;i++){

                       System.out.println("方法参数 "+args[i]); }}

           Object returnvalue =null; //方法的返回值,无返回类型时,为null

           returnvalue=methodProxy.invoke(this.targerObject, args); //调用目标对象的方法

           System.out.println("方法的返回值 "+returnvalue);

        return returnvalue;

}

}

 

这里要引入cglib的相关包:com.springsource.net.sf.cglib-2.1.3.jar,从spring提供的第三方包中获取。

spring中AOP的思想和概念

概念

Aspect(切面): 是通知和切入点的结合,通知和切入点共同定义了关于切面的全部内容---它的功能、在何时和何地完成其功能

joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点.

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

   通知定义了切面的”什么”和”何时”,切入点就定义了”何地”.

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

Target(目标对象):代理的目标对象

Weaving(织入):是指把切面应用到目标对象来创建新的代理对象的过程.切面在指定的连接点织入到目标对象

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

spring在运行期创建代理,不需要特殊的编译器.

4:spring面向切面的编程

Spring提供2个代理模式,一个是jdk代理,另一个cglib代理

1.若目标对象实现了若干接口spring使用JDKjava.lang.reflect.Proxy类代理。

2.若目标对象没有实现任何接口spring使用CGLIB库生成目标对象的子类。

 

注意:开发时尽量使用接口的编程,

(1)对接口创建代理优于对类创建代理,因为会产生更加松耦合的系统。

(2)标记为final的方法不能够被通知。spring是为目标类产生子类。任何需要被通知的方法都被复写,将通知织入。final方法是不允许重写的。

 (3) spring只支持方法连接点,不支持属性的连接点

 

 

(1)配置:

要进行AOP编程首先我们要在spring的配置文件中引入aop命名空间

<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-2.5.xsd

           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

</beans>

 

Spring提供了两种切面使用方式,实际工作中我们可以选用其中一种:

l  基于XML配置方式进行AOP开发。

l  基于注解方式进行AOP开发。

 

SpringAOP编程,需要引入的jar

技术分享

(2)基于XML方式的配置通知

通知类别

before:前置通知(应用:各种校验)

在方法执行前执行,如果其中抛出异常

after:后通知(应用:清理现场)

方法执行完毕后执行,无论方法中是否出现异常

afterReturning:返回后通知(应用:常规数据处理)

方法正常返回后执行,如果方法中抛出异常,无法执行

afterThrowing:抛出异常后通知(应用:包装异常信息)

方法抛出异常后执行,如果方法没有抛出异常,无法执行

around:环绕通知(应用:十分强大,可以做任何事情)

方法执行前后分别执行,可以阻止方法的执行

                            //环绕通知

     public void around(ProceedingJoinPoint pjp) throws Throwable{

              System.out.println("around before......");

              //调用原始方法

              pjp.proceed();

              System.out.println("around after......");

     }

         1.通知的配置格式

                            <aop:before pointcut-ref="pt2" method="before"/>

                            <aop:after pointcut-ref="pt2" method="after"/>

                            <aop:after-returning pointcut-ref="pt2" method="afterReturning"/>

                            <aop:after-throwing pointcut-ref="pt2" method="afterThrowing"/>

                            <aop:around pointcut-ref="pt2" method="around"/>

         2.通知顺序:与配置顺序有关

                   多个切面间

先声明的before先运行,

后声明的before后运行

先声明的after后运行

后声明的after先运行

总结:配置时以最终运行顺序为准

总结:

         AOP:关注共性功能的开发

         共性功能抽出,运行时原始功能错误,必须加入共性功能,原始对象已经无法完成该功能,AOP代理负责 创建一个新的对象,该对象完成原始功能,通过织入操作完成。

         Spring加载上下文时,会读取AOP的配置aop:config,Spring已经知道了哪些方法需要被监控,由切入点实现,当被监控的方法运行时,完成上面一段的操作,加入的功能需要根据配置完成。

         织入:A模块中缺少B功能    BA           A.class

                   编译期植入:A.class中对应的功能已经有BA

                   类加载期植入:A.class中不具有B功能,但是加载A.class时,内存中的类A.class具有B功能

                   运行期植入:执行到时,添加(Spring实现)

前置通知

前置通知:在访问目标对象方法之前,先执行通知,再执行目标对象的方法!

  * 如果通知的方法抛出异常,此时不会执行目标对象中的方法

  * 案例:权限控制,事务处理,校验

 

配置文件如下

    <bean id="security" class="com.itcast.service.Security" />  <!-- 定义切面对象 -->

    <bean id=“userManager” class=“com.itcast.service.UserManagerImpl” />  <!-- 创建接口实现类目标对象 -->

    <aop:config>  <!--所有的切面和通知都必须定义在aop:config元素内部 -->

      <aop:aspect ref="security">  <!-- 配置切面  -->

         <!-- 声明切入点 -->

         <aop:pointcut id="userManagerPointcut"

               expression="execution(* com.itcast.service..*.save*(..))"/>

         <!--声明前置通知,在匹配方法执行前运行-->

         <aop:before method="checkSecurity"  pointcut-ref="userManagerPointcut"/>

       </aop:aspect>

    </aop:config>

 

附录:切入点表达式的练习

<!--

理解切入点中的表达式

execution(* cn.itcast.e_xml.a_before.UserServiceImpl.saveUser(..))

 

execution(

       modifiers-pattern?

       ret-type-pattern

       declaring-type-pattern?

       name-pattern(param-pattern)

        throws-pattern?

        )

除了返回类型模式(上面代码片断中的ret-type-pattern),名字模式和参数模式以外, 所有的部分都是可选的。

返回类型模式决定了方法的返回类型必须依次匹配一个连接点。 你会使用的最频繁的返回类型模式是*,它代表了匹配任意的返回类型。

 一个全限定的类型名将只会匹配返回给定类型的方法。

 名字模式匹配的是方法名。 你可以使用*通配符作为所有或者部分命名模式。

  参数模式稍微有点复杂:()匹配了一个不接受任何参数的方法,

  而(..)匹配了一个接受任意数量参数的方法(零或者更多)。

  模式(*)匹配了一个接受一个任何类型的参数的方法。

  模式(*,String)匹配了一个接受两个参数的方法,第一个可以是任意类型, 第二个则必须是String类型

 

   

   

5个参数:带?号表示非必填项

参数一modifiers-pattern?(非必填项):方法的修饰符

    execution(public * cn.itcast.e_xml.a_before.UserServiceImpl.saveUser(..)):

       方法是公用方法,返回类型任意,在cn.itcast.e_xml.a_before包中的UserServiceImpl,类中的saveUser的方法,参数任意

    execution(private * cn.itcast.e_xml.a_before.UserServiceImpl.saveUser(..)):

       方法是私有方法,返回类型任意,在cn.itcast.e_xml.a_before包中的UserServiceImpl,类中的saveUser的方法,参数任意

参数二ret-type-pattern (必填项):方法的返回值类型

    execution(void cn.itcast.e_xml.a_before.UserServiceImpl.saveUser(..))

       方法是无返回值,在cn.itcast.e_xml.a_before包中的UserServiceImpl,类中的saveUser的方法,参数任意

    execution(java.lang.String cn.itcast.e_xml.a_before.UserServiceImpl.saveUser(..))

       方法的返回值是String类型,在cn.itcast.e_xml.a_before包中的UserServiceImpl,类中的saveUser的方法,参数任意

    execution(* cn.itcast.e_xml.a_before.UserServiceImpl.saveUser(..))

       方法的返回值类型任意,在cn.itcast.e_xml.a_before包中的UserServiceImpl,类中的saveUser的方法,参数任意

参数三declaring-type-pattern? (非必填项):包及其包中的类

    execution(* cn.itcast.e_xml.a_before.UserServiceImpl.saveUser(..))

       方法的返回值类型任意,在cn.itcast.e_xml.a_before包中的UserServiceImpl,类中的saveUser的方法,参数任意

    execution(* cn.itcast.e_xml.a_before.User*.saveUser(..))

       方法的返回值类型任意,在cn.itcast.e_xml.a_before包中,以User开头的类,类中的saveUser的方法,参数任意

    execution(* *.saveUser(..))

       方法的返回值类型任意,在任意包中,任意类,类中的saveUser的方法,参数任意

    execution(* saveUser(..))

       方法的返回值类型任意,在任意包中,任意类,类中的saveUser的方法,参数任意

参数四name-patternparam-pattern)(必填项):方法,括号中表示方法的参数

    方法:

    execution(* cn.itcast.e_xml.a_before.UserServiceImpl.saveUser(..))

       方法的返回值类型任意,在cn.itcast.e_xml.a_before包中的UserServiceImpl,类中的saveUser的方法,参数任意

    execution(* cn.itcast.e_xml.a_before.UserServiceImpl.save*(..))

       方法的返回值类型任意,在cn.itcast.e_xml.a_before包中的UserServiceImpl,类中以save开头的方法,参数任意

    execution(* cn.itcast.e_xml.a_before.UserServiceImpl.*(..))

       方法的返回值类型任意,在cn.itcast.e_xml.a_before包中的UserServiceImpl,类中的所有方法,参数任意

    参数:

    execution(* cn.itcast.e_xml.a_before.UserServiceImpl.saveUser(java.lang.String,java.lang.Integer))

       方法的返回值类型任意,在cn.itcast.e_xml.a_before包中的UserServiceImpl,类中的saveUser的方法,参数有2个,一个是String类型,一个Integetr类型

    execution(* cn.itcast.e_xml.a_before.UserServiceImpl.saveUser())

       方法的返回值类型任意,在cn.itcast.e_xml.a_before包中的UserServiceImpl,类中的saveUser的方法,参数没有参数

    execution(* cn.itcast.e_xml.a_before.UserServiceImpl.saveUser(java.lang.String,*))

       方法的返回值类型任意,在cn.itcast.e_xml.a_before包中的UserServiceImpl,类中的saveUser的方法,参数有2个,一个是String类型,第二个参数是任意类型

    execution(* cn.itcast.e_xml.a_before.UserServiceImpl.saveUser(*))

       方法的返回值类型任意,在cn.itcast.e_xml.a_before包中的UserServiceImpl,类中的saveUser的方法,参数有1个,一个是任意类型的参数

    execution(* cn.itcast.e_xml.a_before.UserServiceImpl.saveUser(..))

       方法的返回值类型任意,在cn.itcast.e_xml.a_before包中的UserServiceImpl,类中的saveUser的方法,参数任意

参数五:throws-pattern?(非必填项):方法抛出的异常

 

重点写法:

    execution(* cn.itcast.e_xml..*.*(..))

       方法的返回值类型任意,在  cn.itcast.e_xml包及其子包中的所有类,类中的所有方法,参数任意

 

 

例子:

任意公共方法的执行:

execution(public * *(..))

 

任何一个名字以“set”开始的方法的执行:

execution(* set*(..))

 

AccountService接口定义的任意方法的执行:

execution(* com.xyz.service.AccountService.*(..))

 

在service包中定义的任意方法的执行:

execution(* com.xyz.service.*.*(..))

 

 

重点:

service包或其子包中定义的任意方法的执行:

execution* com.xyz.service..*.*..))

 

 -->

 

后置通知

后置通知:在访问目标对象方法之后,再执行通知对应的方法!

  * 如果目标对象方法抛出异常,此时不会执行通知的方法

  * 案例:日志备份

  * 特点:可以在通知的方法中添加目标对象方法的返回值!

 

public class Security {

   public void checkSecurity(JoinPoint point,Object retval){

         System.out.println("进行安全性检查");

         //获取目标对象方法的返回值

         System.out.println("retval返回值:    "+retval);

    }

}

配置文件如下

<bean id="security" class="com.itcast.service.Security" /><!-- 定义切面对象 -->

<bean id="userManager" class="com.itcast.service.UserManagerImpl" /><!--创建接口实现类对象-->

    <aop:config>  <!--所有的切面和通知都必须定义在aop:config元素内部 -->

      <aop:aspect ref="security">  <!-- 声明切面  -->

         <!-- 声明切入点 -->

         <aop:pointcut id="userManagerPointcut"

               expression="execution(* com.itcast.service..*.save*(..))"/>

         <!--声明后置通知,在匹配的方法完全执行后运行-->

         <aop:after-returning method="checkSecurity" pointcut-ref="userManagerPointcut“ returning="retval"/>

       </aop:aspect>

    </aop:config>

 

异常通知

异常通知:在访问目标对象方法之后,必须目标对象方法抛出异常,在执行通知中定义的方法

  * 案例:监控信息,如果程序操作正常,不需要给工程师发送一个短信

  * 特点:可以在通知的方法中添加目标对象方法抛出的异常!

 

public class Security {

   public void checkSecurity(JoinPoint point,Throwable ex){

         System.out.println("进行安全性检查");

         //获取异常

         System.out.println("ex   "+ex);        

     }

}

配置文件如下

<bean id="security" class="com.itcast.service.Security" /><!-- 定义切面对象 -->

<bean id="userManager" class="com.itcast.service.UserManagerImpl" /><!--创建接口实现类对象-->

    <aop:config>  <!--所有的切面和通知都必须定义在aop:config元素内部 -->

      <aop:aspect ref="security">  <!-- 声明切面  -->

         <!-- 声明切入点 -->

         <aop:pointcut id="userManagerPointcut"

               expression="execution(* com.itcast.service..*.save*(..))"/>

         <!--声明异常通知,在匹配方法抛出异常退出时执行-->

         <aop:after-throwing method="checkSecurity" pointcut-ref="userManagerPointcut" 

                                                 throwing="ex"/>

       </aop:aspect>

    </aop:config>

 

最终通知

最终通知:在访问目标对象方法之后,不管目标对象是否抛出异常,都会执行通知(后置通知+异常通知)

  * 案例:后置通知+异常通知的特点

配置文件如下

<bean id="security" class="com.itcast.service.Security" /><!-- 定义切面对象 -->

<bean id="userManager" class="com.itcast.service.UserManagerImpl" /><!--创建接口实现类对象-->

    <aop:config>  <!--所有的切面和通知都必须定义在aop:config元素内部 -->

      <aop:aspect ref="security">  <!-- 声明切面  -->

         <!-- 声明切入点 -->

         <aop:pointcut id="userManagerPointcut"

               expression="execution(* com.itcast.service..*.save*(..))"/>

  <!--声明最终通知,在匹配方法退出后执行,不论一个方法是如何结束的,最终通知都会运行-->

         <aop:after method="checkSecurity" pointcut-ref="userManagerPointcut"/>       </aop:aspect>

    </aop:config>

 

环绕通知

环绕通知。环绕通知在一个方法执行之前和之后执行。

  * 它使得通知有机会 在一个方法执行之前和执行之后运行。而且它可以决定这个方法在什么时候执行,如何执行,甚至是否执行。

  * 环绕通知经常在某线程安全的环境下,你需要在一个方法执行之前和之后共享某种状态的时候使用。

  *  请尽量使用最简单的满足你需求的通知。(比如如果简单的前置通知也可以适用的情况下不要使用环绕通知)。

public class Security {

        public Object checkSecurity(ProceedingJoinPoint point){

                 System.out.println("进行安全性检查");

                 //pg自己控制目标方法的调用

                 Object returnvalue=null;

                 try {returnvalue=point.proceed();} catch (Throwable e) {e.printStackTrace();}

                 System.out.println("returnvalue   "+returnvalue);

                 return returnvalue;

        }

}

配置文件如下

<bean id="security" class="com.itcast.service.Security" /><!-- 定义切面对象 -->

<bean id="userManager" class="com.itcast.service.UserManagerImpl" /><!--创建接口实现类对象-->

    <aop:config>  <!--所有的切面和通知都必须定义在aop:config元素内部 -->

      <aop:aspect ref="security">  <!-- 声明切面  -->

         <!-- 声明切入点 -->

         <aop:pointcut id="userManagerPointcut"

               expression="execution(* com.itcast.service..*.save*(..))"/>

            <!--声明环绕通知,可以控制方法的执行-->

            <aop:around method=“checkSecurity”  pointcut-ref=“userManagerPointcut” />

       </aop:aspect>

    </aop:config>

(2)基于注解方式的配置通知

      为了在Spring配置中使用@AspectJ切面,你首先必须启用Spring对@AspectJ切面配置的支持,并确保自动代理 (蓝色部分)

   <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>

   <!--启用Spring对@AspectJ的支持 -->

  <aop:aspectj-autoproxy/>

    <!-- 声明切面对象 -->

    <bean id="security" class="com.itcast.service.Security" />

    <!-- 创建接口实现类对象 -->

    <bean id="userManager" class="com.itcast.service.UserManagerImpl" />

  </beans>

 

前置通知

@Aspect  //声明切面

public class Security {

/**

 *  @Pointcut 用于声明切入点

 *  在@AspectJ注解风格的AOP中 一个切入点签名通过一个普通的方法来定义

 *    1 作为切入点签名的方法必须返回void类型

 *    2 方法没有参数 用private修饰

 *    3 方法体为空

 *    4 方法没有参数

*    切入点表达式的写法

 *    execution(主要)表示匹配方法执行的连接点

 *    例如: * com.itcast.service..*.save*(..))

 *         1 "*"  表示方法的返回类型任意

 *         2 com.itcast.service..*  表示service包及其子包中所有的类

 *         3 .save、delete* 表示类中所有以save或者delete开头的方法

 *         4 (..) 表示参数是任意数量

 */

@Pointcut(“execution(* cn.itcast.service..*.save*(..))")

private void perform(){}

@Pointcut(“execution(* cn.itcast.service..*.delete*(..))")

private void perform2(){}

         /**

 * Before 前置通知 在方法调用前执行

 * perform()|| perform2() 表示前面定义的切入点

*/

      @Before("perform()||perform2()")

public void checkSecurity(JoinPoint point){

         System.out.println("进行安全性检查");

         System.out.println("point.getTarget()  "+point.getTarget());

         //获取方法调用方法的名称

         System.out.println("point.getSignature().getName()   "+point.getSignature().getName());

        //获取方法的参数

         if(point.getArgs()!=null&&point.getArgs().length>0){

         for(int i=0;i<point.getArgs().length;i++){

                System.out.println("point.getArgs()  "+point.getArgs()[i]);        

         }

         }

}

}

后置通知

@Aspect  //声明切面

public class Security {

/**

 *  @Pointcut 用于声明切入点

 *  在@AspectJ注解风格的AOP中 一个切入点签名通过一个普通的方法来定义

 *    1 作为切入点签名的方法必须返回void类型

 *    2 方法没有参数 用private修饰

 *    3 方法体为空

 *    4 方法没有参数

 *    切入点表达式的写法

 *    execution(主要)表示匹配方法执行的连接点

 *    例如: * com.itcast.service..*.save*(..))

 *         1 "*"  表示方法的返回类型任意

 *         2 com.itcast.service..*  表示service包及其子包中所有的类

 *         3 .save* 表示类中所有以save开头的方法

 *         4 (..) 表示参数是任意数量

 */

@Pointcut(“execution(* cn.itcast.service..*.save*(..))")

private void perform(){}

@Pointcut(“execution(* cn.itcast.service..*.delete*(..))")

private void perform2(){}

        /**

 * AfterReturning 后置通知 在一个匹配的方法返回的时候执行

 *   * value 使用的切入点

 *   * returning 表示方法的返回值.方法无返回值时,返回值为空

 *  

 *  * perform()||perform2() 表示前面定义的切入点

 */

         @AfterReturning(value = "perform()||perform2()", returning = "retval")

         public void checkSecurity(JoinPoint point, Object retval) {

              System.out.println("进行安全性检查");

              System.out.println("point.getTarget()  " + point.getTarget());

              // 获取方法调用方法的名称

              System.out.println("point.getSignature().getName()   "+ point.getSignature().getName());

              // 获取方法的参数

             if (point.getArgs() != null && point.getArgs().length > 0) {

                  for (int i = 0; i < point.getArgs().length; i++) {

                       System.out.println("point.getArgs()  " + point.getArgs()[i]);

                  }

             }

            System.out.println("retval   " + retval);//获取返回值的目的,在切入点后可以再执行业务逻辑

        }

}

异常通知

@Aspect  //声明切面

public class Security {

/**

 *  @Pointcut 用于声明切入点

 *  在@AspectJ注解风格的AOP中 一个切入点签名通过一个普通的方法来定义

 *    1 作为切入点签名的方法必须返回void类型

 *    2 方法没有参数 用private修饰

 *    3 方法体为空

 *    4 方法没有参数

 *    切入点表达式的写法

 *    execution(主要)表示匹配方法执行的连接点

 *    例如: * com.itcast.service..*.save*(..))

 *         1 "*"  表示方法的返回类型任意

 *         2 com.itcast.service..*  表示service包及其子包中所有的类

 *         3 .save* 表示类中所有以save开头的方法

 *         4 (..) 表示参数是任意数量

 */

@Pointcut(“execution(* cn.itcast.service..*.save*(..))")

private void perform(){}

@Pointcut(“execution(* cn.itcast.service..*.delete*(..))")

private void perform2(){}

/**

 * AfterThrowing 异常通知,在一个方法抛出异常后执行

 *   * value 使用的切入点

 *   * throwing 表示抛出的异常

 * perform()||perform2() 表示前面定义的切入点

 */

@AfterThrowing(value = "perform()||perform2()", throwing = "ex")

public void checkSecurity(JoinPoint point, Throwable ex) {

        System.out.println("进行安全性检查");

        System.out.println("point.getTarget()  " + point.getTarget());

       // 获取方法调用方法的名称

       System.out.println("point.getSignature().getName()   "+ point.getSignature().getName());

      // 获取方法的参数

      if (point.getArgs() != null && point.getArgs().length > 0) {

            for (int i = 0; i < point.getArgs().length; i++) {

                   System.out.println("point.getArgs()  " + point.getArgs()[i]);

            }

      }

      System.out.println("ex   " + ex);

}

}

最终通知

@Aspect  //声明切面

public class Security {

/**

 *  @Pointcut 用于声明切入点

 *  在@AspectJ注解风格的AOP中 一个切入点签名通过一个普通的方法来定义

 *    1 作为切入点签名的方法必须返回void类型

 *    2 方法没有参数 用private修饰

 *    3 方法体为空

 *    4 方法没有参数

 *    切入点表达式的写法

 *    execution(主要)表示匹配方法执行的连接点

 *    例如: * com.itcast.service..*.save*(..))

 *         1 "*"  表示方法的返回类型任意

 *         2 com.itcast.service..*  表示service包及其子包中所有的类

 *         3 .save* 表示类中所有以save开头的方法

 *         4 (..) 表示参数是任意数量

 */

@Pointcut(“execution(* cn.itcast.service..*.save*(..))")

private void perform(){}

@Pointcut(“execution(* cn.itcast.service..*.delete*(..))")

private void perform2(){}

/**

 * @After 最终通知 不论一个方法如何结束,最终通知都会执行

 *   最终通知必须准备处理正常和异常两种情况,通常用它来释放资源

 * perform()||perform2() 表示前面定义的切入点

 */

       @After(value = "perform()||perform2()")

       public void checkSecurity(JoinPoint point) {

             System.out.println("进行安全性检查");

             System.out.println("point.getTarget()  " + point.getTarget());

            // 获取方法调用方法的名称

           System.out.println("point.getSignature().getName()   "+ point.getSignature().getName());

           // 获取方法的参数

          if (point.getArgs() != null && point.getArgs().length > 0) {

                 for (int i = 0; i < point.getArgs().length; i++) {

                        System.out.println("point.getArgs()  " + point.getArgs()[i]);

                 }

           }

      }

}

环绕通知

@Aspect  //声明切面

public class Security {

/**

 *  @Pointcut 用于声明切入点

 *  在@AspectJ注解风格的AOP中 一个切入点签名通过一个普通的方法来定义

 *    1 作为切入点签名的方法必须返回void类型

 *    2 方法没有参数 用private修饰

 *    3 方法体为空

 *    4 方法没有参数

 *    切入点表达式的写法

 *    execution(主要)表示匹配方法执行的连接点

 *    例如: * com.itcast.service..*.save*(..))

 *         1 "*"  表示方法的返回类型任意

 *         2 com.itcast.service..*  表示service包及其子包中所有的类

 *         3 .save* 表示类中所有以save开头的方法

 *         4 (..) 表示参数是任意数量

 */

@Pointcut(“execution(* cn.itcast.service..*.save*(..))")

private void perform(){}

@Pointcut(“execution(* cn.itcast.service..*.delete*(..))")

private void perform2(){}

/** @Around 环绕通知 可以控制方法的执行

 *    * 通知的第一个参数必须是 ProceedingJoinPoint类型

 *    * 调用ProceedingJoinPoint的proceed()方法会导致 后台的连接点方法执行

 * perform()||perform2() 表示前面定义的切入点

 * @throws Throwable */

        @Around(value = "perform()||perform2()")

       public Object checkSecurity(ProceedingJoinPoint point) {

                System.out.println("进行安全性检查");

                System.out.println("point.getTarget()  " + point.getTarget());

                // 获取方法调用方法的名称

                System.out.println("point.getSignature().getName()   "+ point.getSignature().getName());

                // 获取方法的参数

                if (point.getArgs() != null && point.getArgs().length > 0) {

                      for (int i = 0; i < point.getArgs().length; i++) {

                           System.out.println("point.getArgs()  " + point.getArgs()[i]);

                      }

                }

               //切入点在通知之后执行

               Object returnvalue=null;

               try {returnvalue = point.proceed();}

catch (Throwable e) {

e.printStackTrace();

}

               return returnvalue;

       }

}

 

整合JDBC

使用Spring+JDBC集成需要的jar包

   com.springsource.org.apache.commons.dbcp-1.2.2.osgi.jar

   com.springsource.org.apache.commons.pool-1.5.3.jar

 DBCP连接池需要的jar

  org.springframework.jdbc-3.2.0.RELEASE.jar

  org.springframework.tx-3.2.0.RELEASE.jar

     Spring的jdbc编程需要的jar包

连接数据库的驱动包

junit测试(org.junit\com.springsource.org.junit\4.7.0\com.springsource.org.junit-4.7.0.jar)

使用Spring+JDBC集成步骤如下: 

   <!-- 1 配置dbcp数据源 -->

   <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">

        <property name="driverClassName" value="org.gjt.mm.mysql.Driver"/>

       <!-- &amp; 转义字符 其实就是代表一个& -->

       <property name="url"  value="jdbc:mysql://localhost:3306/itcastdb?useUnicode=true&amp;characterEncoding=UTF-8"/>

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

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

       </bean>

   <!--2  配置JDBC模板 -->

     <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">

          <property name="dataSource" ref="dataSource"/>

     </bean>

   <!-- 配置dao层 -->

   <bean id="accountDao" class="com.itcast.dao.impl.AccountDaoImpl">

         <property name="jdbcTemplate" ref="jdbcTemplate" />

   </bean>

配置数据源(详细)

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">

    <property name="driverClassName" value="org.gjt.mm.mysql.Driver"/>

    <property name="url"   value="jdbc:mysql://localhost:3306/itcastdb?useUnicode=true&amp;characterEncoding=UTF-8"/>

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

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

     <!-- 连接池启动时的初始值 -->

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

          <!-- 连接池的最大值 -->

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

          <!-- 最大空闲值.当经过一个高峰时间后,连接池可以慢慢将已经用不到的连接慢慢释放一部分,一直减少到maxIdle为止 -->

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

          <!--  最小空闲值.当空闲的连接数少于该值时,连接池就会预申请一些连接,以避免洪峰来时再申请而造成的性能开销 -->

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

  </bean>

   上面使用了Apache组织的dbcp数据源,我们需要把lib\jakarta-commons下的commons-dbcp.jar和commons-pool.jar加入类路下。

实现增删改查

public class AccountDaoImpl implements AccountDao {

   

     private JdbcTemplate jdbcTemplate; //声明JDBC模板

     //添加

     public void saveAccount(Account account) throws Exception {

            jdbcTemplate.update("insert into account(accountid,balance) values(?,?)“,

            new Object[]{account.getAccountid(),account.getBalance()},

            new int[]{java.sql.Types.VARCHAR,java.sql.Types.DOUBLE});

     }

    //更新

    public void updateAccount(Account account) throws Exception {

           String sql="update account set balance=? where accountid=?";

           jdbcTemplate.update(sql,

           new Object[]{account.getBalance(),account.getAccountid()},

           new int[]{java.sql.Types.DOUBLE,java.sql.Types.VARCHAR});

     }

//删除

public void deleteAccount(String accountid) throws Exception {

     String sql="delete from account where accountid=?";

     jdbcTemplate.update(sql,

                                        new Object[]{accountid},

                                       new int[]{java.sql.Types.VARCHAR}

                                       );

  }

}

//获取多条记录

public List<Account> findAll() {

       RowMapper rowMapper=new RowMapper(){

                public Object mapRow(ResultSet rs, int rowNum) throws SQLException {

                        Account account=new Account();

                        account.setAccountid(rs.getString(1));

                        account.setBalance(rs.getDouble(2));

                        return account;

                }

       };

       List<Account> list=null;

       String sql="SELECT accountid,balance FROM  account ORDER BY accountid";

       list=this.getJdbcTemplate().query(sql, rowMapper);

       return  list;

}

//获取单条记录,使用id

public Account findAccountById(String id) {

         RowMapper  rowMapper=new RowMapper(){

                 public Object mapRow(ResultSet rs, int rowNum) throws SQLException {

                          Account account=new Account();

                          account.setAccountid(rs.getString(1));

                          account.setBalance(rs.getDouble(2));

                          return account;

                 }

        };

        Account account=null;

        String sql="SELECT accountid,balance FROM  account WHERE accountid=?";

        Object[] args={id};

        account=(Account)this.getJdbcTemplate().queryForObject(sql, rowMapper, args);

        return account;

}

 

spring总结

标签:

原文地址:http://www.cnblogs.com/lulu638/p/4438785.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!