zoukankan      html  css  js  c++  java
  • Spring学习之AOP

    一、操作术语

      连接点(Joinpoint):类里面可以被增强的方法,这些方法称为连接点。

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

      通知/增强(Advice):所谓通知是指拦截到Joinpoint后要做的事情就是通知,通知分为前置通知、后置通知、异常通知、最终通知和环绕通知(切面要完成功能)。

      切面(Aspect):切入点和通知的结合,即把增强应用到具体的方法上面,这个过程称为切面。

      目标对象(Target):代理的目标对象(要增强的类)。

      织入(Weaving):把增强(Advice)应用到目标(Target)的过程。

      代理(Proxy):一个类被aop织入增强后,就产生一个代理结果类

    二、实现策略

      1、JDK动态代理

      使用动态代理可以为一个或多个接口在运行期动态生成实现对象,生成的对象中实现接口的方法时可以添加增强代码,从而实现AOP。缺点是只能针对接口进行代理,另外由于动态代理是通过反射实现的,有时可能要考虑反射调用的开销。

      2、字节码生成(CGLib 动态代理)

      动态字节码生成技术是指在运行时动态生成指定类的一个子类对象,并覆盖其中特定方法,覆盖方法时可以添加增强代码,从而实现AOP。其常用工具是cglib。

      3、定制的类加载器

      当需要对类的所有对象都添加增强,动态代理和字节码生成本质上都需要动态构造代理对象,即最终被增强的对象是由AOP框架生成,不是开发者new出来的。解决的办法就是实现自定义的类加载器,在一个类被加载时对其进行增强。JBoss就是采用这种方式实现AOP功能。

      4、代码生成

      利用工具在已有代码基础上生成新的代码,其中可以添加任何横切代码来实现AOP。

      5、语言扩展

      可以对构造方法和属性的赋值操作进行增强,AspectJ是采用这种方式实现AOP的一个常见Java语言扩展。

    三、编程式增强(无配置文件)

      1、定义接口和实现类

    package com.sgl.aop;
    
    public interface Person {
        void eat(String name);
    }
    package com.sgl.aop;
    
    public class Student implements Person{
    
        @Override
        public void eat(String name) {
            System.out.println("student eat "+name);
        }
    }

      2、编写前置增强和后置增强

    package com.sgl.aop;
    
    import java.lang.reflect.Method;
    import org.springframework.aop.AfterReturningAdvice;
    import org.springframework.aop.MethodBeforeAdvice;
    
    public class BeforeAndAfterAdvice implements MethodBeforeAdvice,AfterReturningAdvice{
    
        @Override
        public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
            System.out.println("after");
        }
    
        @Override
        public void before(Method method, Object[] args, Object target) throws Throwable {
            System.out.println("before");
        }
    
    }

      3、环绕增强

    package com.sgl.aop;
    
    import org.aopalliance.intercept.MethodInterceptor;
    import org.aopalliance.intercept.MethodInvocation;
    
    public class AroundAdvice implements MethodInterceptor{
    
        @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {
            before();
            Object result = invocation.proceed();
            after();
            return result;
        }
    
        public void before(){
            System.out.println("before");
        }
        
        public void after(){
            System.out.println("after");
        }
    }

      4、单元测试

    package com.sgl.aop;
    
    import org.junit.Test;
    import org.springframework.aop.framework.ProxyFactory;
    
    public class TestAop {
        
        @Test
        public void aopTest(){
            //创建代理工厂
            ProxyFactory factory = new ProxyFactory();
            //添加代理目标对象
            factory.setTarget(new Student());
            //添加通知
            factory.addAdvice(new BeforeAndAfterAdvice());
    //        factory.addAdvice(new AroundAdvice());
            //获取代理对象
            Person person = (Person) factory.getProxy();
            person.eat("chicken");
        }
    }

    四、声明式增强(配置文件)

    <?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-4.0.xsd
            http://www.springframework.org/schema/tx
            http://www.springframework.org/schema/tx/spring-tx-4.0.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-4.0.xsd">
    
        <context:component-scan base-package="com.sgl.aop.xml1" />
        
        <bean id="proxyObject" class="org.springframework.aop.framework.ProxyFactoryBean">
            <property name="targetName" value="student" />
            <property name="interceptorNames" value="beforeAndAfterAdvice" />
            <property name="proxyInterfaces" value="com.sgl.aop.xml1.Person" />
        </bean>
    
    </beans>

      在代理目标和增强类添加@Component注解,创建bean

      单元测试:

    package com.sgl.aop.xml1;
    
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class TestAop {
        @Test
        public void test1(){
            ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
            Person person = context.getBean("proxyObject",Person.class);
            person.eat("chicken");
        }
    }

    五、Spring的AspectJ自动代理

      1、基于xml配置文件

    package com.sgl.aop.xml;
    
    /**
     * 被代理的目标类
     */
    public class Math{
        //
        public int add(int n1,int n2){
            int result=n1+n2;
            System.out.println(n1+"+"+n2+"="+result);
            return result;
        }
        
        //
        public int sub(int n1,int n2){
            int result=n1-n2;
            System.out.println(n1+"-"+n2+"="+result);
            return result;
        }
        
        //
        public int mut(int n1,int n2){
            int result=n1*n2;
            System.out.println(n1+"X"+n2+"="+result);
            return result;
        }
        
        //
        public int div(int n1,int n2){
            int result=n1/n2;
            System.out.println(n1+"/"+n2+"="+result);
            return result;
        }
    }
    package com.sgl.aop.xml;
    
    public class Advices{
    
        public void before(){
            System.out.println("----------前置通知----------");
        }
    
        public void after(){
            System.out.println("----------最终通知----------");
        }
    }
    <?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-4.0.xsd
            http://www.springframework.org/schema/tx
            http://www.springframework.org/schema/tx/spring-tx-4.0.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-4.0.xsd">
    
        <!-- 被代理对象 -->
        <bean id="math" class="com.sgl.aop.xml.Math" />
        
        <!-- 通知 -->
        <bean id="advice" class="com.sgl.aop.xml.Advices" />
        
        <!-- aop 配置 -->
        <aop:config>
            <!--切面 -->
            <aop:aspect ref="advice">
                <!-- 切点 -->
                <aop:pointcut expression="execution(* com.sgl.aop.xml.*.*(..))" id="pointcut"/>
                <!--连接通知方法与切点 -->
                <aop:before method="before" pointcut-ref="pointcut"/>
                <aop:after method="after" pointcut-ref="pointcut"/>
            </aop:aspect>
        </aop:config>
    
    </beans>
    package com.sgl.aop.xml;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class Test {
        
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext1.xml");
            Math math = context.getBean("math",Math.class);
            int n1 = 100, n2 = 5;
            math.add(n1, n2);
            math.sub(n1, n2);
            math.mut(n1, n2);
            math.div(n1, n2);
        }
    }

      2、基于注解

    package com.sgl.aop.annotion;
    
    import org.springframework.stereotype.Component;
    
    /**
     * 被代理的目标类
     */
    @Component
    public class Math{
        //
        public int add(int n1,int n2){
            int result=n1+n2;
            System.out.println(n1+"+"+n2+"="+result);
            return result;
        }
        
        //
        public int sub(int n1,int n2){
            int result=n1-n2;
            System.out.println(n1+"-"+n2+"="+result);
            return result;
        }
        
        //
        public int mut(int n1,int n2){
            int result=n1*n2;
            System.out.println(n1+"X"+n2+"="+result);
            return result;
        }
        
        //
        public int div(int n1,int n2){
            int result=n1/n2;
            System.out.println(n1+"/"+n2+"="+result);
            return result;
        }
    }
    package com.sgl.aop.annotion;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.springframework.stereotype.Component;
    @Component
    @Aspect
    public class Advices{
    
        @Before(value="execution(* com.sgl.aop.annotion.*.add*(..))")
        public void before(JoinPoint joinPoint){
            System.out.println("----------前置通知----------");
            System.out.println(joinPoint.getSignature().getName());
        }
    
        @After(value="execution(* com.sgl.aop.annotion.*.*(..))")
        public void after(){
            System.out.println("----------最终通知----------");
        }
    }
    <?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-4.0.xsd
            http://www.springframework.org/schema/tx
            http://www.springframework.org/schema/tx/spring-tx-4.0.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-4.0.xsd">
    
        <context:component-scan base-package="com.sgl.aop.annotion" />
    
        <!-- 开启aop注解扫描 -->
        <aop:aspectj-autoproxy proxy-target-class="true" />
    
    </beans>
    package com.sgl.aop.annotion;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class Test {
        
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext2.xml");
            Math math = context.getBean("math",Math.class);
            int n1 = 100, n2 = 5;
            math.add(n1, n2);
            math.sub(n1, n2);
            math.mut(n1, n2);
            math.div(n1, n2);
        }
    }

      3、定义pointcut,复用切点

    package com.sgl.aop.annotion1;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.AfterReturning;
    import org.aspectj.lang.annotation.AfterThrowing;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    import org.springframework.stereotype.Component;
    @Component
    @Aspect
    public class Advices{
    
        //切点
        @Pointcut(value="execution(* com.sgl.aop.annotion1.*.a*(..))")
        public void pointcut(){
            System.out.println("nihao");
        };
        
        @Before(value="pointcut()")
        public void before(JoinPoint joinPoint){
            System.out.println("----------前置通知----------");
            System.out.println(joinPoint.getSignature().getName());
        }
    
        @After(value="pointcut()")
        public void after(){
            System.out.println("----------最终通知----------");
        }
        
        @Around(value="execution(* com.sgl.aop.annotion1.*.s*(..))")
        public Object around(ProceedingJoinPoint joinPoint) throws Throwable{
            System.out.println("----------环绕前置----------");
            Object result = joinPoint.proceed();
            System.out.println("----------环绕后置----------");
            return result;
        }
        
        //返回结果通知
        @AfterReturning(pointcut="execution(* com.sgl.aop.annotion1.*.m*(..))",returning="result")
        public void afterReturning(JoinPoint jp,Object result){
            System.out.println(jp.getSignature().getName());
            System.out.println("结果是:"+result);
            System.out.println("----------返回结果----------");
        }
        
      //异常后通知
        @AfterThrowing(pointcut="execution(* com.sgl.aop.annotion1.*.d*(..))",throwing="exp")
        public void afterThrowing(JoinPoint jp,Exception exp){
            System.out.println(jp.getSignature().getName());
            System.out.println("异常消息:"+exp.getMessage());
            System.out.println("----------异常通知----------");
        }
    }
    package com.sgl.aop.annotion1;
    
    import org.springframework.stereotype.Component;
    
    /**
     * 被代理的目标类
     */
    @Component
    public class Math{
        //
        public int add(int n1,int n2){
            int result=n1+n2;
            System.out.println(n1+"+"+n2+"="+result);
            return result;
        }
        
        //
        public int sub(int n1,int n2){
            int result=n1-n2;
            System.out.println(n1+"-"+n2+"="+result);
            return result;
        }
        
        //
        public int mut(int n1,int n2){
            int result=n1*n2;
            System.out.println(n1+"X"+n2+"="+result);
            return result;
        }
        
        //
        public int div(int n1,int n2){
            int result=n1/n2;
            System.out.println(n1+"/"+n2+"="+result);
            return result;
        }
    }
    <?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-4.0.xsd
            http://www.springframework.org/schema/tx
            http://www.springframework.org/schema/tx/spring-tx-4.0.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-4.0.xsd">
    
        <context:component-scan base-package="com.sgl.aop.annotion1" />
    
        <!-- 开启aop注解扫描 -->
        <aop:aspectj-autoproxy proxy-target-class="true" /><!-- true表示代理目标类,默认为false,代理接口 -->
    
    </beans>
    package com.sgl.aop.annotion1;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class Test {
        
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext3.xml");
            Math math = context.getBean("math",Math.class);
            int n1 = 100, n2 = 5;
            math.add(n1, n2);
            math.sub(n1, n2);
            math.mut(n1, n2);
            math.div(n1, n2);
        }
    }

      4、自定义配置文件类来代替applicationContext.xml配置文件

    package com.sgl.aop.noxml;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.EnableAspectJAutoProxy;
    
    /**
     * 相当于spring配置文件的类
     * @author suguoliang@daoran.tv
     * @date 2018年4月13日
     */
    @Configuration/*用于表示当前类为容器的配置类,类似<beans/>*/
    @ComponentScan(basePackages={"com.sgl.aop.noxml"})/*扫描的范围,相当于xml的配置<context:component-scan/>*/
    @EnableAspectJAutoProxy(proxyTargetClass=true)/*自动代理,相当于<aop:aspectj-autoproxy proxy-target-class="true" />*/
    public class ApplicationCfg {
        /**
         * 在配置中声明一个bean,相当于<bean id=getUser class="com.sgl.aop.noxml.User"/>
         * @return
         */
        @Bean
        public User getUser(){
            return new User();
        }
    }
    package com.sgl.aop.noxml;
    
    public class User {
        public void show(){
            System.out.println("一个用户对象");
        }
    }
    package com.sgl.aop.noxml;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    
    public class Test {
        
        public static void main(String[] args) {
            ApplicationContext context = new AnnotationConfigApplicationContext(ApplicationCfg.class);
            Math math = context.getBean("math",Math.class);
            int n1 = 100, n2 = 5;
            math.add(n1, n2);
            math.sub(n1, n2);
            math.mut(n1, n2);
            math.div(n1, n2);
        }
    }
  • 相关阅读:
    AutoCAD利用VBA设置线型和添加用户自定义线性
    AutoVBA利用for循环创建同心圆弧
    AutoVBA利用Hacth对象填充图元对象
    AutoVBA利用AddArc方法创建Arc对象
    2011年6月5日星期天
    AutoVBA控件的tabindex和tabstop属性及with语句
    AutoVBA在绘图空间创建直线对象
    AutoVBA利用toolbar创建自己的工具栏
    AutoVBA调用AddCricle方法绘制圆
    AutoCAD利用VBA宏绘制多重平行线
  • 原文地址:https://www.cnblogs.com/a591378955/p/8822995.html
Copyright © 2011-2022 走看看