• 09SpringAopAdvice


    Spring原生的经典模式 实现 AOP
    通知:
        前置通知:在目标方法执行之前执行,不能改变方法的执行流程和结果!
                 实现 MethodBeforeAdvice接口!
        后置通知:在目标方法执行之后执行,不能改变方法的执行流程和结果!
                 实现 AfterReturningAdvice接口!
        环绕通知:方法的拦截器!可以改变方法的执行流程和结果!
                  实现 MethodInterceptor接口!
        异常通知:当我们的目标方法出现异常时才执行的方法!
                  实现ThrowsAdvice接口!
    
    
    
    实现各种增强(通知 advice)的步骤:
    
    01.引入两个jar  一个是aop联盟  spring-aop
    02.创建对应的接口和实现类(主业务)
    03.创建对应的增强处理类(系统级业务)
    04.在spring容器中配置 目标类对象和通知对象
    05.配置ProxyFactoryBean(代理工厂类)
    
    问题:
       01.如果我们有多个serviceImpl! 这时候ProxyFactoryBean不能配置多个目标对象!
       02.ProxyFactoryBean给目标对象中的所有主业务都做了增强!不能指定某个主业务!
    

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <parent>
            <artifactId>Spring</artifactId>
            <groupId>com.xdf</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>09SpringAop</artifactId>
        <packaging>jar</packaging>
    
        <name>09SpringAop</name>
        <url>http://maven.apache.org</url>
    
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <!--spring对应的版本号-->
            <spring.version>4.2.1.RELEASE</spring.version>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>aopalliance</groupId>
                <artifactId>aopalliance</artifactId>
                <version>1.0</version>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.0</version>
                <scope>test</scope>
            </dependency>
    
            <!--引入需要的spring 核心jar-->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>${spring.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-core</artifactId>
                <version>${spring.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-aop</artifactId>
                <version>${spring.version}</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-beans</artifactId>
                <version>${spring.version}</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-expression</artifactId>
                <version>${spring.version}</version>
            </dependency>
    
            <dependency>
                <groupId>commons-logging</groupId>
                <artifactId>commons-logging</artifactId>
                <version>1.1.1</version>
            </dependency>
    
            <!--引入mysql的驱动包-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.26</version>
            </dependency>
    
            <!--配置jdbc需要的数据源-->
            <dependency>
                <groupId>commons-pool</groupId>
                <artifactId>commons-pool</artifactId>
                <version>1.6</version>
            </dependency>
    
            <dependency>
                <groupId>commons-dbcp</groupId>
                <artifactId>commons-dbcp</artifactId>
                <version>1.4</version>
            </dependency>
    
            <dependency>
                <groupId>c3p0</groupId>
                <artifactId>c3p0</artifactId>
                <version>0.9.1.2</version>
            </dependency>
    
            <!--SpringJDBC需要的jar-->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-jdbc</artifactId>
                <version>${spring.version}</version>
            </dependency>
    
    
        </dependencies>
    </project>
    public interface UserService {
    
        //主业务
            String eat();
        //主业务
            void  sleep();
    }
    // 目标类    impl包下的UserServiceImpl
    public class UserServiceImpl   implements UserService{
    
       //主业务
        public String eat() {
            System.out.println("正在吃小苹果......");
            return "apple";
        }
    
        //主业务
        public void sleep() {
            System.out.println("正在休息......");
        }
    }

      定义的通知(增强)

    //异常通知
    public class ExceptionAdvice implements ThrowsAdvice {
    
    
        /**
         * @param ex 用户名异常
         */
        public  void  afterThrowing(UserNameException ex){
            System.out.println(ex.getMessage());
        }
        /**
         * @param ex 年龄异常
         */
        public  void  afterThrowing(AgeException ex){
            System.out.println(ex.getMessage());
        }
    }
    //前置通知
    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("target的名称====》"+target);
            System.out.println("method的名称====》"+method.getName());*/
            System.out.println("执行**** 前置**** 通知");
        }
    }
    //环绕通知
    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;
        }
    }
    //后置通知
    public class AfterAdvice implements AfterReturningAdvice {
        /**
         * 在目标方法执行之后
         * @param returnValue   目标方法的返回值     我们可以获取返回值 但是不能操作返回值
         * @param method   目标方法
         * @param args    目标方法的参数列表
         * @param target    目标对象
         * @throws Throwable
         */
        public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
         /*   System.out.println("target的名称====》"+target);
            System.out.println("returnValue====》"+returnValue);
            System.out.println("method的名称====》"+method.getName());*/
            System.out.println("执行**** 后置**** 通知");
        }
    }

      

      定义的异常文件夹

    //验证异常通知的接口
    public interface ExceptionService {
    
        public  boolean  checkUser(String  userName,int age) throws UserException;
    }
    public class UserServiceImpl implements ExceptionService {
    
        public boolean checkUser(String userName, int age) throws UserException {
            if (!"admin".equalsIgnoreCase(userName)){
                throw  new UserNameException("用户名错误");
            }
            if (age<20){
                throw  new AgeException("年龄错误");
            }
            return true;
        }
    }
    //用户的异常类
    public class UserException  extends  Exception{
    
        public  UserException(String msg){
            super(msg);
        }
    
    }
    //用户名异常类
    public class UserNameException extends  UserException {
    
        public UserNameException(String msg) {
            super(msg);
        }
    }
    //年龄异常类
    public class AgeException extends  UserException {
    
        public AgeException(String msg) {
            super(msg);
        }
    }
    <?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"
           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">
    
        <bean id="userService" class="cn.happy.service.impl.UserServiceImpl"/>
    
        <bean id="before" class="cn.happy.service.advices.BeforeAdvice"/>
    
        <bean id="after" class="cn.happy.service.advices.AfterAdvice"/>
    
        <bean id="around" class="cn.happy.service.advices.AroundAdvice"/>
    
        <bean id="userException" class="cn.happy.service.exceptionPackage.UserServiceImpl"/>
    
        <bean id="myException" class="cn.happy.service.advices.ExceptionAdvice"/>
    
        <!--03.通知配置代理工厂bean,生成代理类,来把通知织入到目标对象
        问题:只能管理 通知!
        01.只能将切面织入到目标类的所有方法中
        02.只能配置一个目标对象
        -->
        <bean id="userProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
            <property name="target" ref="userService"/>
            <!--前置,后置的通知: value第一种方法-->
            <!--<property name="interceptorNames" value="before,after"/>-->
            <!--前置,后置,环绕的通知 value第二种方法-->
            <property name="interceptorNames">
                <array><!--这里要定义array-->
                    <value>before</value>
                    <value>after</value>
                    <value>around</value>
                </array>
            </property>
        </bean>
    
        <bean id="exceptionProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
            <property name="targetName" value="userException"/>
            <property name="interceptorNames">
                <array>
                    <value>myException</value>
                </array>
            </property>
            <!--代理类的优化  是否使用cglib动态代理-->
            <property name="optimize" value="true"/>
        </bean>
    </beans>

    <property name="proxyTargetClass" value="true"/>
            proxyTargetClass:默认是false,默认执行jdk动态代理!
                            设置成true,强制执行cglib!
            optimize:代理类的优化
                    有接口就是用jdk,没有接口使用cglib动态代理

    我们的动态代理 (在程序运行期间,动态生成的代理类) 分为两种方式:
      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);
            }
        }
  • 相关阅读:
    Educational Codeforces Round 72 (Rated for Div. 2)
    2249: Altruistic Amphibians 01背包
    lh的简单图论
    E. XOR Guessing 交互题 Educational Codeforces Round 71 (Rated for Div. 2)
    C. Helga Hufflepuff's Cup 树形dp 难
    B. Marvolo Gaunt's Ring 前缀后缀
    android学习-IPC机制之ACtivity绑定Service通信
    大数组分时加载算法 timedChunk
    log4j 配置和使用
    fastjson 配置和使用
  • 原文地址:https://www.cnblogs.com/Chenghao-He/p/7662383.html
Copyright © 2020-2023  润新知