zoukankan      html  css  js  c++  java
  • Spring笔记07(Spring AOP的通知advice和顾问advisor)

    1.Spring AOP的通知advice

    01.接口代码:

    package cn.pb.dao;
    
    public interface UserDao {
        //主业务
        String add();
        //主业务
        void del();
    }

    02.实现类代码:

    package cn.pb.dao;

    public class UserDaoImpl implements UserDao{
    //主业务
    public String add() {
    //模拟异常
    //int a=8/0;
    System.out.println("add ok!");
    return "新增成功!";
    }
    //主业务
    public void del() {
    System.out.println("del ok!");
    }

    03.增强通知类:

    001.前置增强类:

    package cn.pb.advices;
    /**
     * 前置增强类 实现MethodBeforeAdvice接口
     * 在目标对象方法执行之前执行
     */
    
    import org.springframework.aop.MethodBeforeAdvice;
    
    import java.lang.reflect.Method;
    
    public class BeforeAdvice implements MethodBeforeAdvice {
        /**
         *
         * @param method :目标方法
         * @param args  :目标方法参数
         * @param target :目标对象
         * @throws Throwable
         */
        public void before(Method method, Object[] args, Object target) throws Throwable {
            System.out.println("前置增强====================》");
        }
    }

    002.后置增强类:

    package cn.pb.advices;
    /**
     * 后置增强类 实现AfterReturningAdvice接口
     * 在目标对象方法执行之后执行
     */
    import org.springframework.aop.AfterReturningAdvice;
    
    import java.lang.reflect.Method;
    
    public class AfterAdvice implements AfterReturningAdvice {
        /**
         *
         * @param target:目标对象
         * @param method :目标方法
         * @param args :目标方法参数
         * @param returnValue :目标方法返回值
         * @throws Throwable
         */
        public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
            System.out.println("后置增强==================》");
        }
    }

    003.环绕增强类:

    package cn.pb.advices;
    /**
     * 环绕增强 :
     * 在前置通知 之后,
     * 后置通知之前执行环绕通知!
     */
    
    import org.aopalliance.intercept.MethodInterceptor;
    import org.aopalliance.intercept.MethodInvocation;
    
    public class AroundAdvice implements MethodInterceptor {
        /**
         * 在前置通知 之后,后置通知之前执行环绕通知!
         * 可以获取方法的返回值,并且改变!
         * @param methodInvocation 方法的执行器, getMethod 包含了方法中的所有方法
         * @return
         */
        public Object invoke(MethodInvocation methodInvocation) throws Throwable {
            System.out.println("执行方法之前的  环绕通知");
            //执行目标方法
            Object result= methodInvocation.proceed();
            if (result!=null){
                //对方法的返回值进行修改
                result="xiaoheihei";
            }
            System.out.println("执行方法之后的  环绕通知");
            return result;
        }
    }

    004.异常增强类:

    package cn.pb.advices;
    
    /**
     * 异常增强类:在目标方法出现异常的时候执行
     * 实现ThrowsAdvice接口
     */
    
    import org.springframework.aop.ThrowsAdvice;
    
    
    
    public class ExceptionAdvice implements ThrowsAdvice{
        public void throwsAdvice(){
            System.out.println("方法在执行过程中出现了异常!");
        }
    }

    04.applicationContext.xml文件:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="
            http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <!--01.配置目标对象-->
        <bean id="userDao" class="cn.pb.dao.UserDaoImpl"/>
        <!--02.配置通知-->
        <bean id="beforeAdvice" class="cn.pb.advices.BeforeAdvice"/>
        <bean id="afterAdvice" class="cn.pb.advices.AfterAdvice"/>
        <bean id="aroundAdvice" class="cn.pb.advices.AroundAdvice"/>
    
        <!--03.通过配置代理工厂bean,生成代理类,来把通知织入到目标对象
          问题:只能管理  通知!
             01.只能将切面织入到目标类的所有方法中!
             02.只能配置一个 目标对象
       -->
        <bean id="userProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
            <!--注册目标对象  如果nam为target 那么ref="userDao" -->
            <property name="targetName" value="userDao"/>
            <!--注册通知-->
            <property name="interceptorNames" value="beforeAdvice,afterAdvice,aroundAdvice"/>
    
        </bean>
    
    
    
        <!--配置异常目标对象-->
        <bean id="userException" class="cn.pb.exceptionPackage.UserServiceImpl"/>
        <!--配置异常通知-->
        <bean id="myException" class="cn.pb.advices.ExceptionAdvice"/>
    
        <!--现在是一个service对应一个ProxyFactoryBean  这样不可以!-->
        <bean id="exceptionProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
            <!--注册目标对象 -->
            <property name="targetName" value="userException"/>
            <!--注册通知-->
            <property name="interceptorNames">
                <array>
                    <value>myException</value> <!--异常通知-->
                </array>
            </property>
            <!--代理类的优化  设置之后程序就会自动选择是使用JDK动态代理还是使用cglib动态代理-->
            <property name="optimize" value="true"/>
            <!-- <property name="proxyTargetClass" value="true"/>
                proxyTargetClass:默认是false  ,默认执行jdk动态代理!
                                  设置成true,强制执行cglib!
                optimize :  代理类的优化
                             有接口就是用jdk,没有接口使用cglib动态代理-->
        </bean>
    <!--
          我们的动态代理 (在程序运行期间,动态生成的代理类) 分为两种方式:
             01.jdk     只能应用于实现接口的情况
             02.cglib   应用于实现接口和类的情况
             如果我们是接口的情况,使用jdk效率高!
             如果我们是类的情况,必须使用cglib!
            问题?
               程序  spring容器怎么知道我们是用的类还是接口??
              public class ProxyConfig implements Serializable
                private boolean proxyTargetClass = false;
                private boolean optimize = false;
                spring底层默认使用cglib! 现在我们的项目中使用的是接口!
                用spring默认的性能不高!
               proxyTargetClass 和optimize都是用来设置 我们使用的代理模式是jdk还是cglib!
               @Override
        public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
           根据我们配置文件中 proxyTargetClass 和 optimize的配置
            if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
                Class<?> targetClass = config.getTargetClass();
                if (targetClass == null) {
                    throw new AopConfigException("TargetSource cannot determine target class: " +
                            "Either an interface or a target is required for proxy creation.");
                }
               根据目标对象返回对应的动态代理
                if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
                    return new JdkDynamicAopProxy(config);
                }
                return new ObjenesisCglibAopProxy(config);
            }
            else {
                return new JdkDynamicAopProxy(config);
            }
        }
    -->
    
    </beans>

    05.测试代码:

    package cn.pb;
    
    import cn.pb.dao.UserDao;
    import cn.pb.exceptionPackage.ServiceException;
    import cn.pb.exceptionPackage.UserException;
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class TestAdvice {
    
        /**
         *  前置  后置 通知测试
         */
    
        @Test
        public    void   testBefore(){
            ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
            UserDao service= (UserDao) context.getBean("userProxy");
            service.add();
            System.out.println("*************");
            service.del();
        }
    
    
        /**
         * 环绕 通知测试
         */
    
        @Test
        public    void   testAround(){
            ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
            UserDao service= (UserDao) context.getBean("userProxy");
            String result= service.add();
            System.out.println(result);
            System.out.println("*************");
            service.del();
        }
    
    
        /**
         *  异常通知测试
         */
    
        @Test
        public    void   testException(){
            ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
            ServiceException service= (ServiceException) context.getBean("exceptionProxy");
            try {
                service.chechUser("admins",25);
            } catch (UserException e) {
                e.printStackTrace();
            }
    
        }
    
    }

     

    2.Spring AOP的顾问advisor

    01.readMe

    顾问:在通知的基础之上,在细化我们的aop切面!
    
    通知和顾问都是切面的实现方式!
    通知是顾问的一个属性!
    
    顾问会通过我们的设置,将不同的通知,在不通过的时间点,把切面
    织入到不同的切入点!
    
    PointCutAdvisor接口!
    比较常用的两个实现类:
    NameMatchMethodPointcutAdvisor :根据切入点(主业务方法)名称织入切面!
    RegexpMethodPointcutAdvisor :根据自定义的正则表达式织入切面!
    
    
    正则表达式中常用的三个运算符
    .   任意单个字符
    +   表示字符出现一次或者多次
    *   表示字符出现0次或者多次

    02.接口代码:

    package cn.pb.dao;
    
    public interface UserDao {
        //主业务
        void  add();
        //主业务
        void  del();
    }

    03.实现类代码:

    package cn.pb.dao.impl;
    
    import cn.pb.dao.UserDao;
    
    public class UserDaoImpl implements UserDao{
    
        //主业务
        public void add() {
            System.out.println("add ok!");
        }
        //主业务
        public void del() {
            System.out.println("del ok!");
        }
    }

    04.增强类代码:

    package cn.pb.advices;
    /**
     * 前置增强类 在目标方法执行之前 执行
     * 要实现MethodBeforeAdvice接口
     */
    
    import org.springframework.aop.MethodBeforeAdvice;
    
    import java.lang.reflect.Method;
    
    public class BeforeAdvice implements MethodBeforeAdvice {
        /**
         * 在目标方法执行之前
         * @param method   目标方法
         * @param args    目标方法的参数列表
         * @param target    目标对象
         * @throws Throwable
         */
        public void before(Method method, Object[] args, Object target) throws Throwable {
            System.out.println("前置增强==============》");
        }
    }

    05.applicationContext.xml文件:

    001.NameMatchMethodPointcutAdvisor :根据切入点(主业务方法)名称织入切面!

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="
            http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <!--01.配置目标对象-->
        <bean id="userDao" class="cn.pb.dao.impl.UserDaoImpl"/>
        <!--02.配置增强 通知-->
        <bean id="beforeAdvice" class="cn.pb.advices.BeforeAdvice"/>
    
    
        <!---配置顾问   实现了 在指定的主业务方法中 增强-->
        <bean id="myAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
            <!--通知就是顾问中的一个属性-->
            <property name="advice" ref="beforeAdvice"/>
            <!--配置切入点   这里的切入点指的是 方法的简写!-->
            <property name="mappedNames" value="add,del"/>
        </bean>
    
        <!--03.配置代理对象-->
        <bean id="userProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
            <!--注册目标对象-->
            <property name="target" ref="userDao"/>
            <!--注册顾问-->
            <property name="interceptorNames" value="myAdvisor"/>
        </bean>
    
    </beans>

    002.RegexpMethodPointcutAdvisor :根据自定义的正则表达式织入切面!

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="
            http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <!--01.配置目标对象-->
        <bean id="userDao" class="cn.pb.dao.impl.UserDaoImpl"/>
        <!--02.配置增强 通知-->
        <bean id="beforeAdvice" class="cn.pb.advices.BeforeAdvice"/>
    
    
        <!---配置顾问   实现了 在指定的主业务方法中 增强-->
        <bean id="myAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
            <!--通知就是顾问中的一个属性-->
            <property name="advice" ref="beforeAdvice"/>
            <!--配置切入点   这里的切入点指的是 方法的全限定方法名
              cn.pb.dao.impl.UserServiceImpl.add
               cn.pb.dao.impl.UserServiceImpl.del-->
            <!-- <property name="pattern" value=".*add.*"/>  匹配单个方法-->
            <!-- <property name="pattern" value=".*mpl.*"/>匹配多个方法-->
            <!--<property name="patterns" value=".*add.*,.*del.*"/>  匹配多个方法-->
            <property name="pattern" value=".*add.*|.*del.*"/>
    
    
    </bean>
    
    <!--03.配置代理对象-->
        <bean id="userProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
            <!--注册目标对象-->
            <property name="target" ref="userDao"/>
            <!--注册顾问-->
            <property name="interceptorNames" value="myAdvisor"/>
        </bean>
    
    </beans>

    06.测试代码:

    package cn.pb;
    
    import cn.pb.dao.UserDao;
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class TestUser {
        /**
         * 测试NameMatchMethodPointcutAdvisor
         */
        @Test
        public void testNameMethod(){
            ApplicationContext context=new
                    ClassPathXmlApplicationContext("applicationContext.xml");
           UserDao proxy= (UserDao) context.getBean("userProxy");
           proxy.add();
            System.out.println("***************");
            proxy.del();
        }
    
        /**
         * 测试RegexpMethodPointcutAdvisor
         */
        @Test
        public void testRegexpMethod(){
            ApplicationContext context=new
                    ClassPathXmlApplicationContext("regexp.xml");
            UserDao proxy= (UserDao) context.getBean("userProxy");
            proxy.add();
            System.out.println("***************");
            proxy.del();
        }
    }
  • 相关阅读:
    ado.net 完整修改删除,攻击防攻击
    ado.net 修改,查询
    navicat连接sqlserver未指定默认驱动程序
    设计模式之Proxy(代理)(转)
    设计模式之Prototype(原型)(转)
    设计模式之Observer(观察者)(转)
    设计模式之Memento(备忘机制)(转)
    设计模式之Mediator(中介者)(转)
    设计模式之Interpreter(解释器)(转)
    信步漫谈之Xfire—基础介绍
  • 原文地址:https://www.cnblogs.com/lyb0103/p/7658781.html
Copyright © 2011-2022 走看看