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

java的动态代理的两种方式和spring的aop面向切面编程的对比

时间:2019-10-07 17:45:37      阅读:89      评论:0      收藏:0      [点我收藏+]

标签:equals   参数   intercept   stat   for   ssl   tip   test   win   

java动态代理的两种方式
使用动态代理的好处:可以进行类的功能的加强,同时减少耦合和代码的冗余,耦合的意思是不用吧加强的部分写到各个实现类里面,冗余的意思是如果对每个实现类加强的部分是一样的,通过一个代理类即可实现
 
  • 基于jdk的动态代理
          通过jdk中自带的Proxy类进行动态的代理,Proxy创建动态代理对象的时候要传入三个参数,第一个是classloader,第二个是interfaces,第三个是代理类实现的方法
          要求:代理的是一个接口,必须至少有一个实现类
          创建接口的代码:
/**
* author:Chen
* date:2019/10/7 14:04
*/
public interface IActor {
    public void sing(String money);
    public void actor();
}

public class Actor implements IActor {
     //只要参数传进来的时候是有钱的
    public void sing(String money) {
        System.out.println("演员唱歌");
    }

    public void actor() {
        System.out.println("演员演戏");
    }
}

/**
* 使用jdk自带的Proxy类实现动态代理
*/
@Test
public void demo04(){
    //创建一个接口的实现类的对象
    final Actor actor=new Actor();
    IActor proxyActor = (IActor)Proxy.newProxyInstance(actor.getClass().getClassLoader(), Actor.class.getInterfaces(), new InvocationHandler() {
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //将实现类的对象作为对象传入进去执行对应重写的方法
            Object proxy_actor=null;
            String name = method.getName();
            if(name.equals("sing"))
            {
                double money = Double.parseDouble((String)args[0]);
                if (money>1000d){//可以对金额进行判断,同时可以将一些不合法的参数进剔除
                    proxy_actor= method.invoke(actor, args);
                }
                else
                {
                    System.out.println("不能唱歌,钱太少了");
                }
            }
            return proxy_actor;//必须要将invoke执行返回的代理对象返回
        }
    });
    //将钱交给经纪人进行判定是否要唱歌,实现了动态代理的功能
    proxyActor.sing("1000");
}

  

tips:无法通过返回值的类型来判定重载,必须通过参数的个数、参数的类型、参数的顺序来判定重载。返回值无法判定重载的原因是
          调用方法的时候没有指定返回值的类型,编译器不知道要调用哪个方法
好处:不用接口,可以轻易的将一个类的所有方法进行代理,也就是更改,而不改变原始的类,缺点是所有的方法都会进行拦截。
  • 使用CGLib中的Enhancer类来创建代理对象
/**
*  必须要引入cglib的包
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.1</version>
</dependency>
* 执行被代理类的方法的时候,进行拦截,不需要实现接口
*/
@Test
public void demo05() {
    final Actor actor = new Actor();
    Actor proxy_actor = (Actor) Enhancer.create(Actor.class, new MethodInterceptor() {
        //创建一个方法拦截器来进行拦截
        public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            Object rtvalue = null;
            if (method.getName().equals("sing")) {
                if (Double.parseDouble((String) args[0]) > 1000) {
                    rtvalue = method.invoke(actor, args);
                }
                else
                {
                    System.out.println("不能唱歌");
                }
            }
            return rtvalue;
        }
    });
    proxy_actor.sing("999");
}

  

 
  • spring的aop面向对象编程的方式
   通过aop接口进行事务的控制
   aop中的相关的术语:
    Joinpoint:连接点
    pointCut:切入点,需要代理的业务方法就是切入点
    aspect:切面,就是要放在切入点前后执行的一个对象,将这个对象的方法配置成切入点的各种通知
    before:前置通知,在切入点执行之前执行
    after-returning:后置通知,当切入点执行完成的时候执行
    after-throwing:异常通知,当发生异常的时候执行
    after:最终通知,无论发生什么,在最后执行
    切入点表达式:execution(* com.huawei.sevice.impl.*.*(..))     返回值类型(用通配符*表示) 包名.类名.方法名()   ..代表的是通配有参和无参    也可以完整写法通配的写法为 * *..*.*(..)   *..通配所有的包名  tips:在引入依赖的时候一定要引入切入点表达式的解析包
    Advice:增强
    Introduce:引介
一个小demo,用前置,后置,异常,最终通知配置,将logger类的方法加入进去
spring的配置文件  完整的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"
      xmlns:context="http://www.springframework.org/schema/context"
      xmlns:aop="http://www.springframework.org/schema/aop"
      xmlns:tx="http://www.springframework.org/schema/tx"
      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
      http://www.springframework.org/schema/aop
      http://www.springframework.org/schema/aop/spring-aop.xsd
      http://www.springframework.org/schema/tx
      http://www.springframework.org/schema/tx/spring-tx.xsd">
    <!--将切入点的bean配置-->
    <bean id="accountService" class="com.huawei.service.impl.AccountServiceImpl"></bean>
    <!--将切面的bean进行配置-->
    <bean id="logger" class="com.huawei.utils.Logger"></bean>
    <!--配置切面-->
    <aop:config>
        <aop:aspect id="loggeradvice" ref="logger" >
            <!--前置通知-->
            <aop:before method="before_printLog" pointcut="execution(* com.huawei.service.impl.AccountServiceImpl.*(..))"></aop:before>
            <!--后置通知-->
            <aop:after-returning method="afterreturning_printLog" pointcut="execution(* com.huawei.service.impl.AccountServiceImpl.*(..))" ></aop:after-returning>
            <!--异常通知-->
            <aop:after-throwing method="afterthrowing_printLog" pointcut="execution(* com.huawei.service.impl.AccountServiceImpl.*(..))"></aop:after-throwing>
            <!--最终通知-->
            <aop:after method="after_printLog" pointcut="execution(* com.huawei.service.impl.AccountServiceImpl.*(..))"></aop:after>
        </aop:aspect>
    </aop:config>
</beans>


public class SpringTest {
    public static void main(String[] args) {
        //必须通过spring的方式获取的对象,才能实现aop
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
        AccountService accountService = (AccountService)applicationContext.getBean("accountService");
        accountService.saveAccount(account);//执行的时候将携带那些通知
    }
}

小demo,通过在代码中写代码进行环绕通知的配置
<?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"
      xmlns:tx="http://www.springframework.org/schema/tx"
      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
      http://www.springframework.org/schema/aop
      http://www.springframework.org/schema/aop/spring-aop.xsd
      http://www.springframework.org/schema/tx
      http://www.springframework.org/schema/tx/spring-tx.xsd">
    <!--将切入点的bean配置-->
    <bean id="accountService" class="com.huawei.service.impl.AccountServiceImpl"></bean>
    <!--将切面的bean进行配置-->
    <bean id="logger" class="com.huawei.utils.Logger"></bean>
    <!--配置切面-->
    <aop:config>
        <!--配置通用的切入点-->
        <aop:pointcut id="pt-1" expression="execution(* com.huawei.service.impl.AccountServiceImpl.*(..))"></aop:pointcut>
        <aop:aspect id="loggeradvice" ref="logger" >
          <!--  <!–前置通知–>
            <aop:before method="before_printLog" pointcut="execution(* com.huawei.service.impl.AccountServiceImpl.*(..))"></aop:before>
            <!–后置通知–>
            <aop:after-returning method="afterreturning_printLog" pointcut="execution(* com.huawei.service.impl.AccountServiceImpl.*(..))" ></aop:after-returning>
            <!–异常通知–>
            <aop:after-throwing method="afterthrowing_printLog" pointcut="execution(* com.huawei.service.impl.AccountServiceImpl.*(..))"></aop:after-throwing>
            <!–最终通知–>
            <aop:after method="after_printLog" pointcut="execution(* com.huawei.service.impl.AccountServiceImpl.*(..))"></aop:after>-->
            <!--环绕通知-->
            <aop:around method="around_printLog" pointcut-ref="pt-1"></aop:around>
        </aop:aspect>
    </aop:config>
</beans>

  

java的动态代理的两种方式和spring的aop面向切面编程的对比

标签:equals   参数   intercept   stat   for   ssl   tip   test   win   

原文地址:https://www.cnblogs.com/jeasonchen001/p/11631264.html

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