精华内容
下载资源
问答
  • 2017-08-10 14:53:41

    使用注解来创建切面AspectJ 5 所引入的关键特性。

    我们前一篇已经定义了 Performance 接口,它是切面中切点的目标对象

    Q:如何定义切面?

    A: 给出一个描述:如果一场演出没有观众的话,那就不能称之为演出。对不对?从演出的角度来看,观众是非常重要的,但是对演出本身的功能来将,它并不是核心,这是一个单独的关注点。因此,将观众定义为一个切面,并将其应用到演出上就是较为明智的做法。

    之前需要在 build.gradle 导入 aspectjrt

    // https://mvnrepository.com/artifact/org.aspectj/aspectjrt
    compile group: 'org.aspectj', name: 'aspectjrt', version: '1.9.0.BETA-6'
    package concert;
    
    import org.aspectj.lang.annotation.AfterReturning;
    import org.aspectj.lang.annotation.AfterThrowing;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    
    /**
     * 该类使用 @AspectJ 注解进行了标注。该注解表明该类不仅仅是一个 POJO,还是一个切面。
     * 该类中的方法都使用注解来定义切面的具体行为。
     */
    @Aspect
    public class Audience {
    
        //表演之前:将手机调至静音状态
        @Before("execution(**concert.Performance.perform(..))")
        public void silenceCellPhones() {
            System.out.println("Silencing cell phones");
        }
    
        //表演之前:就座
        @Before("execution(**concert.Performance.perform(..))")
        public void takeSeats() {
            System.out.println("Taking seats");
        }
    
        //表演之后:精彩的话,观众应该会鼓掌喝彩
        @AfterReturning("execution(**concert.Performance.perform(..))")
        public void applause() {
            System.out.println("CLAP CLAP CLAP!!!");
        }
    
        //表演失败之后:没有达到观众预期的话,观众会要求退款
        @AfterThrowing("execution(**concert.Performance.perform(..))")
        public void demandRefund() {
            System.out.println("Demanding a refund");
        }
    
    }

    可以简化一下,使用 @Pointcut 注解。

    package concert;
    
    import org.aspectj.lang.annotation.AfterReturning;
    import org.aspectj.lang.annotation.AfterThrowing;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    
    /**
     * 简化方案:@Pointcut 注解能够在一个 @AspectJ 切面内定义可重用的切点。
     */
    @Aspect
    public class Audience {
    
        //通过在该方法上添加 @Pointcut 注解,我们实际上扩展了切点表达式语言,
        //这样就可以在任何的切点表达式中使用 performance()了。
        //该方法内容并不重要,实际上应该是空的。只是一个标识,供 @Pointcut 注解依附。
        @Pointcut("execution(**concert.Performance.perform(..))")
        public void performance(){}
    
        //表演之前:将手机调至静音状态
        @Before("performance()")
        public void silenceCellPhones() {
            System.out.println("Silencing cell phones");
        }
    
        //表演之前:就座
        @Before("performance()")
        public void takeSeats() {
            System.out.println("Taking seats");
        }
    
        //表演之后:精彩的话,观众应该会鼓掌喝彩
        @AfterReturning("performance()")
        public void applause() {
            System.out.println("CLAP CLAP CLAP!!!");
        }
    
        //表演失败之后:没有达到观众预期的话,观众会要求退款
        @AfterThrowing("performance()")
        public void demandRefund() {
            System.out.println("Demanding a refund");
        }
    
    
    }
    

    AspectJ 提供了五个注解来定义通知。
    这里写图片描述

    package concert;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.EnableAspectJAutoProxy;
    
    /**
     * 如果你使用 JavaConfig 的话,可以在配置类的类级别上通过使用 @EnableAspectJAutoProxy 注解启用自动代理功能。
     */
    @Configuration
    @EnableAspectJAutoProxy //启用 AspectJ 自动代理
    @ComponentScan
    public class ConcertConfig {
    
        @Bean
        public Audience audience(){  // 声明 Audience bean
            return new Audience();
        }
    }
    

    或者 XML 中配置:使用 Spring aop 命名空间中的 aop:aspectJ-autoproxy 元素。

    <?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.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">
    
        <context:component-scan base-package="concert"/>
    
        <!-- 启用 AspectJ 自动代理 -->
        <aop:aspectj-autoproxy/>
    
        <!-- 声明 Audience bean -->
        <bean class="concert.Audience"/>
    
    </beans>

    不管使用 JavaConfig 还是 XML,AspectJ 自动代理都会为使用 @Aspect 注解的 bean 创建一个代理,这个代理会围绕着所有该切面的切点所匹配的 bean。在这种情况下,将会为 Concert bean 创建一个代理,Audience 类中的通知方法将会在 perform() 调用前后执行。

    需要记住的是:Spring 的 AspectJ 自动代理仅仅使用 @AspectJ 作为创建切面的指导,切面依然是基于代理的。本质上,它依然是 Spring 基于代理的切面。这就意味着,尽管使用的是 @AspectJ 注解,但我们仍然限于代理方法的调用。如果想利用 AspectJ 的所有能力,我们必须在运行时使用 AspectJ 并且不依赖于 Spring 来创建基于代理的切面

    Q:如何创建环绕通知?

    A: 环绕通知是最为强大的通知类型。实际上就像在一个通知方法中同时编写前置通知和后置通知。

    package concert;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Pointcut;
    
    /**
     * 使用环绕通知重新实现 Audience 切面
     * 这个通知所达到的效果跟之前的前置后置通知是一样的。但是,现在它们位于一个方法中。
     */
    @Aspect
    public class Audience {
    
        // 定义命名的切点
        @Pointcut("execution(**concert.Performance.perform(..))")
        public void performance(){}
    
        /**
         * 环绕通知方法
         * @param joinPoint 这个对象是必须要有的,因为你要在通知中通过它来调用被通知的方法。
         */
        @Around("performance()")
        public void watchPerformance(ProceedingJoinPoint joinPoint){
            try {
                System.out.println("Silencing cell phones");
                System.out.println("Taking seats");
                // 通知方法中可以做任何的事情,当要将控制权交给被通知的方法时,它需要调用该方法。
                // 如果不调用这个方法的话,那么你的通知实际上会阻塞对被通知方法的调用。
                // 有可能这就是你想要的效果,但更多的情况是你希望在某个点上执行被通知的方法。
                joinPoint.proceed();
                System.out.println("CLAP CLAP CLAP!!!");
            } catch (Throwable throwable) {
                System.out.println("Demanding a refund");
            }
        }
    
    }
    

    对于 proceed() 方法,你也可以在通知中对它进行多次调用,这样做的一个场景就是实现重试逻辑,也就是在被通知方法失败后,进行重复尝试

    Q:如何处理通知的参数?(切面能访问和使用传递给被通知方法的参数吗?)

    A:如下列代码所示:BlankDisc.java & CompactDisc.java 参考 Spring 如何通过 XML 装配 bean?,并加以修改 play() 方法。

    package concert;
    
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * 假设你想记录每个磁道被播放的次数。由于记录磁道的播放次数与播放本身是不同的关注点,因此应该是切面要完成的任务。
     * 使用参数化的通知来记录磁道播放的次数
     */
    @Aspect
    public class TrackCounter {
    
        // 记录每个磁道播放次数
        private Map<Integer, Integer> trackCounts = new HashMap<Integer, Integer>();
    
        // 通知 play() 方法,在切点表达式中声明参数,这个参数传入到通知方法 countTrack() 中
        // args(trackNumber) 表明传递给 play() 方法的 int 类型参数也会传递到通知中(countTrack()方法)去。
        // 参数名称与切点方法签名中的参数相匹配。
        @Pointcut("execution(* soundsystem.CompactDisc.play(int)) && args(trackNumber)")
        public void trackPlayed(int trackNumber) {
        }
    
        // 在播放之前,为该磁道计数
        // 这个通知方法是通过 @Before 注解和命名切点 trackPlayed(trackNumber) 定义的。
        // 切点定义中的参数与切点方法中的参数名称是一样的,这样就完成了从命名切点到通知方法的参数转移。
        @Before("trackPlayed(trackNumber)")
        public void countTrack(int trackNumber) {
            int currentCount = getPlauCount(trackNumber);
            trackCounts.put(trackNumber, currentCount + 1);
        }
    
        public int getPlauCount(int trackNumber) {
            return trackCounts.containsKey(trackNumber) ? trackCounts.get(trackNumber) : 0;
        }
    
    }
    
    package soundsystem;
    
    import concert.TrackCounter;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.EnableAspectJAutoProxy;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 在 Spring 配置中将 BlankDisc 和 TrackCounter 定义为 bean,并启用自动代理。
     * 配置 TrackCount 记录每个磁道播放的次数
     */
    @Configuration
    @EnableAspectJAutoProxy // 启用 AspectJ 自动代理
    public class TrackCounterConfig {
    
        @Bean
        public CompactDisc sgtPeppers(){
            BlankDisc cd = new BlankDisc();
            cd.setTitle("titleValue01");
            cd.setArtist("ArtistValue01");
            List<String> tracks = new ArrayList<String>();
            tracks.add("trackValue01");
            tracks.add("trackValue02");
            tracks.add("trackValue03");
            tracks.add("trackValue04");
            tracks.add("trackValue05");
            cd.setTracks(tracks);
            return cd;
        }
    
        @Bean
        public TrackCounter trackCounter(){
            return new TrackCounter();
        }
    
    }
    

    Q:如何通过注解引入新功能?

    A: Java 不是动态语言,一旦类编译完成了,我们就很难再为该类添加新功能了。但是我们可以使用切面,为对象拥有的方法添加了新功能,而没有为对象添加任何新的方法。实际上,利用被称为引入的 AOP 概念,切面可以为 Spring bean 添加新的方法

    这里写图片描述

    注意:当引入接口的方法被调用时,代理会把此调用委托给实现了新接口的某个其他对象。实际上,一个 bean 的实现被拆分到了多个类中

    代码如下:

    package concert;
    
    /**
     * 为所有的 Performance 实现引入下面的 Encoreable 接口
     *
     * 需要将这个接口应用到 Performance 实现中。
     * 两个问题:不能直接实现 Encoreable 接口,并不是所有的 Performance 都是具有 Encoreable 特性的;
     *           也有可能无法修改所有的 Performance 实现(使用第三方实现并且没有源码时)。
     * 解决方案:借助于 AOP 的引入功能,我可以避免以上两个问题。
     */
    public interface Encoreable {
        void performEncore();
    }
    
    package concert;
    
    /**
     * Encoreable 接口的实现类
     */
    public class DefaultEncoreable implements Encoreable {
        @Override
        public void performEncore() {
    
        }
    }
    
    package concert;
    
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.DeclareParents;
    
    /**
     * 创建一个切面
     */
    @Aspect
    public class EncoreableIntroducer {
    
        // 通过 @DeclareParents 注解,将 Encoreable 接口引入到 Performance bean 中。
        // @DeclareParents 注解由三部分组成:
        // ①、value 属性指定了哪种类型的 bean 要引入该接口。
        //     此处 value 的值,代表所有实现 Performance 的类型。(标记符后面的 "+" 表示是 Performance 的所有子类型,而不是它本身)
        // ②、defaultImpl 属性指定了为引入功能提供实现的类。这里,指定的是 DefaultEncoreable 提供实现。
        // ③、@DeclareParents 注解所标注的静态属性指明了要引入的接口。这里,所引入的是 Encoreable 接口。
        @DeclareParents(value = "concert.Performance+",defaultImpl = DefaultEncoreable.class)
        public static Encoreable encoreable;
    
    }
    
        <!-- 将 EncoreableIntroducer 声明为一个 bean -->
        <bean class="concert.EncoreableIntroducer"/>

    Spring 的自动代理机制将会获取到它的声明,当 Spring 发现了一个 bean 使用了 @Aspect 注解时,Spring 就会创建一个代理,然后将调用委托给被代理的 bean被引入的实现,这取决于调用的方法属于被代理的 bean 还是属于被引入的接口

    面向注解的切面声明有一个明显的劣势你必须能够为通知类添加注解。为了做到这一点,必须要有源码。

    如果没有源码的话,或者不想将 AspectJ 注解放到你的代码之中,我们可以在 Spring XML 配置文件中声明切面。

    上一篇: 面向切面的 Spring —— 如何通过切点来选择连接点?
    下一篇:面向切面的 Spring —— 如何在 XML 中声明切面?

    更多相关内容
  • 电动切面机图纸.pdf

    2019-09-19 02:22:00
    电动切面机图纸pdf,电动切面机图纸
  • 针对红会一矿综采面切眼使用综掘扩掘工期长、劳动强度大等问题,决定选用MG-300/700-QWD型采煤进行眼大断面扩掘技术,研究了采煤扩刷及支护技术,并对眼扩掘期间的安全技术措施进行了论述,对综采面切眼扩掘...
  • 行业文档-设计装置-三面切的底座结构.zip
  • 行业分类-设备装置-三面切的刀架调节机构.zip
  • 行业文档-设计装置-三面切出书压书装置.zip
  • 行业分类-设备装置-三面切的压纸机构.zip
  • 行业分类-设备装置-三面切的书本推送机构.zip
  • 行业文档-设计装置-三面切中整书上的皮带调节机构.zip
  • 靖远煤业集团有限责任公司红会第一煤矿在1703综放工作采用了大断面眼采煤扩掘技术,不仅缩短了工作的搬家安装时间,而且降低工人劳动强度、提高了工效,经济效益十分显著。
  • 行业分类-设备装置-用于三面切的书本输送装置.zip
  • 行业资料-交通装置-一种三面切的盘车控制电路.zip
  • 面切安全操作规程.doc
  • 为了实现三面切侧刀和前刀自动调节,参照传统三面切刀具调节方法,设计了一种数字印刷三面切刀具调节系统。该系统主要由 PC ( personal computer)、单片机、步进电机、驱动器、丝杠及控制界面构成。在...
  • 特别是综采工作面切眼需要扩帮时,快速提升眼扩帮的速度,将直接影响到综采工作的设备安装工作。以陈四楼煤矿2513外眼扩帮为例,对如何提升扩帮速度、缩短设备安装等待时间进行了研究。采煤在扩帮施工中的应用,...
  • 行业文档-设计装置-三面切刀片木盒
  • 随着市场对中厚板平面度等精度及断口切面质量要求的提高,通过对中厚板加工剪切后的质量分析,设计了一种滚切式双边剪,用来剪切材料为钢材的中厚板,应用结果表明,该剪具有剪切能力大,剪切质量高,且材料利用率高等...
  • 介绍了东滩煤矿在二分层综采工作面切眼导硐内安装液压支架、输送、采煤以及利用采煤扩刷眼的工艺,有效地缩短了综采设备安装调试期,实现了在破碎顶板条件下成功地利用采煤自行扩刷眼。
  • 行业文档-设计装置-一种用于三面切的刀胎底座开合的调节机构.zip
  • 行业文档-设计装置-带电磁离合制动装置的三面切.zip
  • 行业文档-设计装置-一种三面切的侧刀座抱紧装置
  • 结合小青煤矿W2-713工作眼的实例,介绍了刨煤工作眼断面形式对初采的影响,总结了在实际生产过程中的经验和做法,从更改眼断面设计入手,着重对眼的施工方法、技术要求以及支护参数进行了分析,给出了...
  • 工作巷回柱硐室扩帮施工安全技术措施.docx
  • 电子政务-具有涂粘膜保护的风力发电叶片及叶尖.zip
  • 在高压区复合顶板情况下,探索出使用综掘进行眼开帮,同时进行采区设备安装,为类似条件的矿井综采安装,提供可借鉴的相关经验。
  • Unity3D摄像远、近切面绘制

    千次阅读 2019-08-15 13:00:05
    最近在研究unity3D的Debug.DrawLine, 就利用该函数绘制了U3D上Mian Camera---Perspective模式下的近切面、远切面。思路来源:https://www.xuanyusong.com/archives/3036 接下来回顾一下unity3D camera绘制远、近...

    最近在研究unity3D的Debug.DrawLine, 就利用该函数绘制了U3D上Mian Camera---Perspective模式下的近切面、远切面。思路来源:https://www.xuanyusong.com/archives/3036

    接下来回顾一下unity3D camera绘制远、近切面的相关组件:

    (1)首先选择摄像机的投影方式,Camera包括透视投影、正交投影两种(如下图),选择透视投影

             1.orthographic正交摄像机:投影线垂直于投影面,也叫平行投影;

             2.perspective透视摄像机:犹如我们的眼睛一样,会根据距离的远近显示 大小;

                 

    (2)Field of View   视角(只有在透视投影时才有的特性)

             即: 视角越大,能看到的视野也越大,对应的焦距也越短

    (3)Clipping Planes 裁剪平面,Near和Far指定了裁剪的区域范围

           远近裁剪平面和Field Of view决定的平面一起构成一个椎体,被称为相机椎体或视椎体(如下图)

    (4)接下来新建脚本Draw.cs将其挂在maincamera上:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class Draw : MonoBehaviour
    {

        private Camera theCamera;

        public float NearDistance = 0.3f;

        public float FarDistance = 1000.0f;
        private Transform tx;

        // Start is called before the first frame update
        void Start()
        {
            if (!theCamera)
            {
                theCamera = Camera.main;
            }
            tx = theCamera.transform;
        }

        // Update is called once per frame
        void Update()
        {
            FindUpperCorners();
            FindLowerCorners();
        }
        void FindUpperCorners()
        {
            NearDistance = theCamera.GetComponent<Camera>().nearClipPlane;
            Vector3[] corners = GetCorners(NearDistance);

            // for debugging
            Debug.DrawLine(corners[0], corners[1], Color.yellow); // UpperLeft -> UpperRight
            Debug.DrawLine(corners[1], corners[3], Color.yellow); // UpperRight -> LowerRight
            Debug.DrawLine(corners[3], corners[2], Color.yellow); // LowerRight -> LowerLeft
            Debug.DrawLine(corners[2], corners[0], Color.yellow); // LowerLeft -> UpperLeft
        }

        void FindLowerCorners()
        {
            FarDistance = theCamera.GetComponent<Camera>().farClipPlane;
            Vector3[] corners = GetCorners(FarDistance);

            // for debugging
            Debug.DrawLine(corners[0], corners[1], Color.red);
            Debug.DrawLine(corners[1], corners[3], Color.red);
            Debug.DrawLine(corners[3], corners[2], Color.red);
            Debug.DrawLine(corners[2], corners[0], Color.red);
        }


        Vector3[] GetCorners(float distance)
        {
            Vector3[] corners = new Vector3[4];

            float halfFOV = (theCamera.fieldOfView * 0.5f) * Mathf.Deg2Rad;
            float aspect = theCamera.aspect;

            float height = distance * Mathf.Tan(halfFOV);
            float width = height * aspect;

            // UpperLeft
            corners[0] = tx.position - (tx.right * width);
            corners[0] += tx.up * height;
            corners[0] += tx.forward * distance;

            // UpperRight
            corners[1] = tx.position + (tx.right * width);
            corners[1] += tx.up * height;
            corners[1] += tx.forward * distance;

            // LowerLeft
            corners[2] = tx.position - (tx.right * width);
            corners[2] -= tx.up * height;
            corners[2] += tx.forward * distance;

            // LowerRight
            corners[3] = tx.position + (tx.right * width);
            corners[3] -= tx.up * height;
            corners[3] += tx.forward * distance;

            return corners;
        }

    }
    (5)运行效果

    展开全文
  • 以卸ZF13000/25/38型支架为例对提升能力进行计算,经在工作安装应用效果可知:该设备的使用大大提高重型设备的卸车效率,有效地解决了特厚放顶煤工作准备期间重型支架进入巷后卸车的问题。
  • 梧桐庄矿182811工作面切眼净宽6 m,长度216 m,采用综掘施工大断面眼一次成巷,出煤系统由传统铺设3~4部SGB-620/40T型号刮板输送接力运输更改为铺设一部简易胶带输送出煤,提高了掘进效率,节省了支护材料费用和...
  • 对大断面厚煤层综放工作面切眼掘进一次成巷施工技术进行了探索,并在东易煤矿90101综采工作应用,采用EBZ160悬臂式综掘掘进割煤,配合掘进二运转载机、40 t溜子出煤,全断面掘进分两次施工,掘进割煤先施工老塘侧...
  • 在火焰数控割炬运动分析的基础上,定义了表达割炬轨迹所需的参考和相关参数,建立了带坡口角的管-管相贯、管-板相贯相贯线数学模型,提出了最大z坐标原则求K形接头相贯线的方法。对管-管相贯、 K形接头相贯...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 57,574
精华内容 23,029
关键字:

切面机