您的位置:首页 > 编程语言 > Java开发

【Java EE 学习 51】【Spring学习第三天】【cglib动态代理】【AOP和动态代理】【切入点表达式】

2015-09-30 22:29 846 查看

一、cglib动态代理

  1.简介

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

    (2) 用CGlib生成代理类是目标类的子类。

    (3)用CGlib生成 代理类不需要接口

    (4)用CGLib生成的代理类重写了父类的各个方法。

    (5)拦截器中的intercept方法内容正好就是代理类中的方法体

  2.Spring什么时候使用JDK动态代理,什么时候使用CGLib动态代理?

    (1)若目标对象实现了若干接口,spring使用JDK的java.lang.reflect.Proxy类代理。

       优点:因为有接口,所以使系统更加松耦合

       缺点:为每一个目标类创建接口

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

       优点:因为代理类与目标类是继承关系,所以不需要有接口的存在。

       缺点:因为没有使用接口,所以系统的耦合性没有使用JDK的动态代理好。

  3.不使用Spring,使用CGlib动态代理示例。

package com.kdyzm.spring.proxy.xml;

public class Transaction {
public void startTransaction(){
System.out.println("开启事务!");
}
public void commit(){
System.out.println("提交事务!");
}
}


com.kdyzm.spring.proxy.xml.Transaction
      最重要的是配置文件,这里不需要明确使用哪种代理方式,因为没有给目标类加上要实现的接口,所以spring会自动使用CGLib动态代理方式,通过debug模式可以看出来。

<?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:context="http://www.springframework.org/schema/context"
    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/context http://www.springframework.org/schema/context/spring-context-2.5.xsd            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
            ">
<bean id="personDao" class="com.kdyzm.spring.proxy.xml.PersonDaoImpl"></bean>
<bean id="transaction" class="com.kdyzm.spring.proxy.xml.Transaction"></bean>

<aop:config>
<!-- 切入点表达式确定哪个类能够生成代理对象 -->
<aop:pointcut expression="execution(* com.kdyzm.spring.proxy.xml.PersonDaoImpl.*(..))" id="aimClass"/>
<!-- 切面 -->
<aop:aspect ref="transaction">
<aop:before method="startTransaction" pointcut-ref="aimClass"/>
<aop:after method="commit" pointcut-ref="aimClass"/>
</aop:aspect>
</aop:config>
</beans>


      可以发现配置文件的命名空间多了一个,而且需要另外的一个schema约束。

xmlns:aop="http://www.springframework.org/schema/aop
 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd


      测试类:com.kdyzm.spring.proxy.xml.AOPTest

package com.kdyzm.spring.proxy.xml;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AOPTest {
@Test
public void testOne(){
ApplicationContext context=new ClassPathXmlApplicationContext("com/kdyzm/spring/proxy/xml/applicationContext.xml");
PersonDaoImpl personDaoImpl = (PersonDaoImpl) context.getBean("personDao");
personDaoImpl.deletePerson();
}
}


      运行结果:

开启事务!
删除学生!
提交事务!


      使用的代理方式一定是CGLib:

      


  3.各种通知

    (1)前置通知

      形式

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


      在切面Transaction中的对应方法中,可以加上JoinPoint参数,通过该参数能够获取目标类的目标方法名称、参数值等信息。

public void startTransaction(JoinPoint joinPoint){
System.out.println("开始事务!");
}


    (2)后置通知

<aop:after-returning method="commit" pointcut-ref="aimClass" returning="val"/>


      目标方法执行完成之后执行该通知,通知中可以带有两个参数,JoinPoint joinPoint和Object val。

      joinPoint:通过该对象能够获取目标类和目标方法的一切信息,包括目标方法的参数列表。

      val:通过该对象能够获取目标方法执行之后的返回值,如果没有返回值,则val为null;val一定要和方法中的参数名称完全相同。

    注意:如果在执行目标类的目标方法中遇到异常,则不执行后置通知。

    (3)异常通知

<aop:after-throwing method="exceptionMethod" pointcut-ref="aimClass" throwing="ex"/>


      切面中的通知可以带有两个参数:JoinPoint joinPoint,Throwalbe ex

      ex一定要与throwing="ex"中的相同。

    (4)环绕通知

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


      环绕通知的作用就是拦截目标方法的执行,可以在执行之前和执行之后做一些动作。

      切面中的通知可以有一个参数:ProceedingJoinPoint joinPoint,该接口是JoinPoint的子接口,所以通过该接口的引用仍然能够获取想要获取到的有关目标类和目标方法的所有信息。另外,该类提供了procced方法,用于执行目标方法。

public void aroundTest(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("拦截方法的执行!");
joinPoint.proceed();
}


    (5)最终通知

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


      最终通知大多数用于释放在执行目标方法的时候占用的资源,即使产生了异常,后置通知不被执行,但是最终通知一定会被执行。  

      也就是说在最终通知中不受异常的影响。也就是说不论目标方法执行的过程中是否抛出异常,最终通知都将执行。

四、切入点表达式

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)
throws-pattern?)


   除了返回类型模式(上面代码片断中的ret-type-pattern),名字模式和参数模式以外, 所有的部分都是可选的。返回类型模式决定了方法的返回类型必须依次匹配一个连接点。 你会使用的最频繁的返回类型模式是
*
,它代表了匹配任意的返回类型。 一个全限定的类型名将只会匹配返回给定类型的方法。名字模式匹配的是方法名。 你可以使用
*
通配符作为所有或者部分命名模式。 参数模式稍微有点复杂:
()
匹配了一个不接受任何参数的方法, 而
(..)
匹配了一个接受任意数量参数的方法(零或者更多)。 模式
(*)
匹配了一个接受一个任何类型的参数的方法。 模式
(*,String)
匹配了一个接受两个参数的方法,第一个可以是任意类型, 第二个则必须是String类型。更多的信息请参阅AspectJ编程指南中 语言语义的部分。

  1.execution(public * *(..))

    任意的公有方法

  2.execution(* set*(..))

    任意以set开头的方法

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

    com.xyz.service.AccountService接口或者类中的所有方法

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

    com.xyz.service包下的所有类的所有方法

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

    com.xyz.service包及子包下的所有类的所有方法

  6.execution(* com.xyz.service.*.*(String,*))

    com.xyz.service包及子包下的所有类中的第一个参数类型为String,第二个参数任意的所有方法。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: