Spring学习(三)之AOP及JDBC模板

一.动态代理

1.1 动态代理的原理

    代理设计模式的原理:使用一个代理将对象封装起来,然后用代理对象取代原始对象,任何对原始对象的调用都要通过代理,代理对象决定是否以及一何种方式将方法调用转到原始对象上。

1.2动态代理的方式

1.基于接口实现动态代理:JDK动态代理
2.基于继承实现动态代理:Cglib、javassist动态代理

1.JDK的动态代理
  (1) Proxy
    它是所有动态代理类的父类,专门用来生成代理类或者是代理对象。

//用来生成代理类的Class对象
public static Class<?> getProxyClass(ClassLoader loader,Class<?>... interfaces)
//用来生成代理对象
/**
  loader:ClassLoader对象,类加载器对象,帮我们加载动态生成的代理类;
  interfaces:接口们,提供目标对象的所有接口。
  h:InvocationHandler 对象
**/
 ClassLoader loader = target.getClass().getClassLoader();
 Class[] interfaces = target.getClass().getInterfaces();
public static Object newProxyInstance(ClassLoader loader,Class<?>... interfaces,InvocationHandler h)

  (2) InvocationHandler
    由它完成动态代理的整个过程

//invoke :代理对象调用代理方法,会回来调用invoke方法
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;
//在该方法中包含Object result=method.invoke(target,args);该语句是目标对象执行目标方法

  动态代理需要明白:目标对象,如何获取代理对象以及代理要做什么。实际上,动态代理类是在运行时动态生成的,因此如果需要查看该动态代理类,需要将内存中的东西抓出来,只需在测试方法中加入如下代码来保存动态生成的代理类:

//将动态生成的代理类保存下来
Properties properties = System.getProperties();
properties.put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");

  动态代理类中最重要的核心代码就是在某方法中执行如下语句:

super.h.invoke(this,m1,...);

二.AOP概述

  2.1 AOP
    AOP编程操作的主要对象是切面,而切面模块化横切关注点,横切关注点我们可以理解为功能,将这些功能抽取出来单独作为一个个的功能。在应用AOP编程时,仍然需要定义公共功能,但可以明确的定义这个功能应用在哪里,以什么方式应用,并且不必修改受影响的类,这样一来横切关注点就被模块化到特殊的类里——这样的类我们通常称为切面。比如验证功能、前置日志功能、后置日志功能等可以抽取出来成为验证切面、日志切面。
    AOP底层实际上就是动态代理。

1.切面:切面就是封装横切关注点信息的类,每个关注点体现为一个通知方法。
2.通知:通知就是切面必须完成的每个具体的工作,目标即就是被通知的对象。
3.代理:代理则是向目标对象应用通知之后创建的代理对象。
4.连接点:连接点则是横切关注点在程序代码中的具体体现,对应程序执行的某个特定位置,例如:类某个方法调用前、调用后、方法捕获到异常后等。
5.切入点:切入点则是定位连接点的方式,每个类的方法中包含多个连接点,所以连接点是类中客观存在的事物,如果把连接点看作数据库中的记录,那么切入点就是查询条件,AOP可以通过切入点定位到特定的连接点。

二、AspectJ

  AspectJ并不是spring本身的AOP框架,它是java社区里最完整最流行的AOP框架,在spring2.0以上版本中,可以使用AspectJ注解或者基于xml配置的AOP。AspectJ既支持JDK的代理又支持Cglib的代理。

2.1 AspectJ引入

<!--组件扫描-->
<context:component-scan base-package="com.atguigu.spring.aspectJ.annotation"></context:component-scan>
<!--基于注解使用AspectJ:主要作用就是为切面中通知能作用到的目标类生成代理-->
<aop:aspectj-autoproxy/>

  在AspectJ注解中,切面只是一个带有@Aspect注解的java类,它往往包含很多通知。通知时标注了某种注解的简单java方法。AspectJ支持5中类型的通知注解。通知注解的使用一般需要在方法上包含切入点表达式,比如@Before(value=“execution(public int com.xxx.xxImpl.方法名(参数列表类型))”)

1.@Before:前置通知,在方法之前执行;
2.@After:后置通知,在方法执行之后执行;
3.@AfterRunning:返回通知,在方法返回结果之后执行;
4.@AfterThrowing:异常通知,在方法抛出异常之后执行;
5.@Around:环绕通知,围绕着方法执行。
  如果希望通知注解作用到任意方法上,可以使用:

@Before("execution(* com.xxx.*.*(..))")

  其中,第一个*:表示任意修饰符,任意返回值;第二个*:表示任意类;第三个*:任意方法;..:表示任意参数列表。

2.2 返回通知

  通过参数列表中定义接收方法返回值的形参,即获取方法的返回值是通过returning 来指定一个名字,必须要与方法的一个形参名一致:

@AfterReturning(value="execution(* com.xxx.*.*(..)),returning=“result")
public void afterReturningMethod(JoinPoint joinPoint, Object result){
   //方法的名字
   String methodName=joinPoint.getSignature().getName();
   //其他代码
}

2.3 异常通知

  异常通知是在目标方法抛出异常后执行。获取异常信息时在注解中使用throwing=”变量名“来获取异常信息。如下:

@AfterThrowing(value="execution(* com.xxx.*.*(..)),throwing=“ex")
public void afterReturningMethod(JoinPoint joinPoint, Exception ex){
   //方法的名字
   String methodName=joinPoint.getSignature().getName();
   //其他代码
}

  获取方法的异常时,通过throwing来指定一个名字,必须要与方法的一个形参名一致。可以通过形参中异常的类型来设置抛出指定异常才会执行异常通知。如果想要在方法抛出空指针异常时才执行的话,那么就需要:

@AfterThrowing(value="execution(* com.xxx.*.*(..)),throwing=“ex")
public void afterThrowingMethod(JoinPoint joinPoint,NullPoint Exception ex){
   //方法的名字
   String methodName=joinPoint.getSignature().getName();
   //其他代码
}

2.4 环绕通知

  环绕通知可以理解为环绕这目标方法执行,可以理解为前置、后置、返回以及异常通知的结合体,更像是动态代理的整个过程。

@Around(value="execution(* com.xxx.*.*(..)))
public Object aroundMethod(ProceedingJoinPoint pjp){
   //执行目标方法
   try{
        //前置通知
        Object result = pjp.proceed();
        //返回通知
        return result;
   }catch(Throwable e){
       //异常通知
       e.printStackTrace();
   }finally{
        //后置通知
   }  
   return null;
}

2.5 切面的优先级

  当有多个切面作用于同一目标对象时,这时往往需要设置各切面的优先级,此时可以在切面类上通过Order(数值)注解来设置切面的优先级,默认为2147483647,为最大值,却是最低的优先级,值越小,其优先级越高,因此当设置值为1时,优先级最高。

2.6 重用切入点表达式

  当切面中的通知多次用到同一个切入点表达式时,可以将切入点表达式声明为一个方法:

public class LoggingAspect{
     //声明切入点表达式
     @PointCut("execution(* com.xxx.*.*(..)))
     public void declarePointCut(){}
     //同一类中重用切入点表达式
     @After(“declarePointCut()”)
     public void afterMethod(JoinPoint joinPoint){
          //方法的名字
         String methodName=joinPoint.getSignature().getName();
          //其他代码
      }
}

  不同切面类重用切入点表达式:

public class ValidationAspect{
     //不同类中重用切入点表达式
     @After(“ LoggingAspect.declarePointCut()”)
     public void afterMethod(JoinPoint joinPoint){
          //方法的名字
         String methodName=joinPoint.getSignature().getName();
          //其他代码
      }
}

三、以XML方式配置切面

<!--目标对象-->
<bean id="arithmticCalculatorImpl" class="com.atguigu.spring.aspectJ.xml.ArithmeticCalculatorImpl"></bean>
<!--切面-->
<bean id="loggingAspect" class="com.atguigu.spring.aspectJ.xml.LoggingAspect"></bean>
<bean id="validationAspect" class="com.atguigu.spring.aspectJ.xml.ValidationAspect"></bean>
<!--aop:切面 通知 切入点表达式-->
<aop:config>
     <!--切面1-->
     <aop:aspect ref="loggingAspect" order=“2”>
         <!--切入点表达式-->
         <aop:pointcut expression="execution(* com.atguigu.spring.aspectJ.xml.*.*(..))"  id="myPointCut"/>
          <!--通知-->
          <aop:before method="beforeMethod"  pointcut-ref="myPointCut"/>
          <!--如果切入点表达式不一样,可以采用如下pointcut重新指定切入点表达式-->
          <aop:after method="afterMethod"  pointcut="execution(* com.atguigu.spring.aspectJ.xml.*.*(..))"  pointcut-ref="myPointCut"/>
          <aop:after-returning method="afterReturningMethod"  pointcut-ref="myPointCut" returning="res"/>
          <aop:after-throwing method="afterThrowingMethod"  pointcut-ref="myPointCut" throwing="ex"/>
          <aop:around method="aroundMethod"  pointcut-ref="myPointCut"/>
     </aop:aspect>
     <!--切面2-->
     <aop:aspect ref="validationAspect" order=“1”>
         <!--切入点表达式-->
         <aop:pointcut expression="execution(* com.atguigu.spring.aspectJ.xml.*.*(..))"  id="myPointCut"/>
          <!--通知-->
          <aop:before method="beforeMethod"  pointcut-ref="myPointCut"/>
          <!--如果切入点表达式不一样,可以采用如下pointcut重新指定切入点表达式-->
          <aop:after method="afterMethod"  pointcut="execution(* com.atguigu.spring.aspectJ.xml.*.*(..))"  pointcut-ref="myPointCut"/>
          <aop:after-returning method="afterReturningMethod"  pointcut-ref="myPointCut" returning="res"/>
          <aop:after-throwing method="afterThrowingMethod"  pointcut-ref="myPointCut" throwing="ex"/>
          <aop:around method="aroundMethod"  pointcut-ref="myPointCut"/>
     </aop:aspect>
</aop:config>

四、JdbcTemplate

4.1 概述

  Spring在JDBC API上定义了一个抽象层,以此建立一个JDBC存取框架。JDBC模板的设计目的时为了不同类型的JDBC操作提供模板方法,通过这种方式,可以在尽可能保留灵活性的情况下,将数据库存取的工作量降到最低。可以将Spring的JdbcTemplate看作是一个小型的轻量级持久化框架。

4.2 xml配置

<!---数据源->
<context:property-placeholder location="classpath:db,properties"/>
<bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
      <property name="driverClass" value="${jdbc.driver}"></property>
      <property name="jdbcUrl" value="${jdbc.url}"></property>
      <property name="user" value="${jdbc.username}"></property>
      <property name="password" value="${jdbc.password}"></property>
 </bean>
 
<!--JdbcTemplate-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
     <property name="dataSource" ref="dataSource"></property>
</bean>          

4.3 持久化操作

1.update():增删改操作
 (1)定义sql语句的字符串
    String sql = “insert into stu(id,name,sex) value(?,?,?)”;
 (2)调用方法
    dbcTemplate.update(sql,sql语句参数列表);
2.batchUpdate(String List<Object[]>):批量增删改
3.queryForObject(String, RowMapper,Object…):查询单行
4.query(String, RowMapper,Object ):查询多行
5.queryForObject(String,Class,Object…):查询单一值

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值