美文网首页
12、面向切面的Spring(补)(spring笔记)

12、面向切面的Spring(补)(spring笔记)

作者: yjaal | 来源:发表于2017-05-17 11:41 被阅读46次

    之前书中的例子代码不全,这里我们通过几个例子来演示说明spring aop的功能。

    一、基本的 AOP 使用

    工程结构

    1

    首先定义切面 SecurityHandler.java

    package win.iot4yj.spring.aspect;
    import org.aspectj.lang.ProceedingJoinPoint;
    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;
    
    /**
     * 
     * @author yj
     * 这个类就是一个切面
     */
    
    @Aspect
    @Component
    public class SecurityHandler {
        
        //定义一个切点,只是相当于一个标识。即匹配所有add开头的方法,参数和返回值任意。而allAddMethod方法不能有返回值
        @Pointcut("execution(* add*(..))")
        private void allAddMethod(){}
        
        //这个方法就相当于一个通知,标识在哪个切入点织入
        @Before("allAddMethod()")
        private void checkSevurity(){
            System.out.println("-------安全性检查-------");
        }
    }
    

    说明:切点的标识方法可以有参数,但不能有返回值。

    业务类 UserManager.java UserManagerImpl.java

    package win.iot4yj.spring.manager;
    public interface UserManager {
        
        public void addUser(String username, String password);
    }
    
    package win.iot4yj.spring.manager;
    import org.springframework.stereotype.Component;
    
    @Component("userManager")
    public class UserManagerImpl implements UserManager {
    
        @Override
        public void addUser(String username, String password) {
            System.out.println("-------添加用户-------");
        }
    }
    

    配置类 Config.java

    package win.iot4yj.spring.config;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.EnableAspectJAutoProxy;
    import win.iot4yj.spring.aspect.SecurityHandler;
    import win.iot4yj.spring.manager.UserManager;
    
    @Configuration
    @EnableAspectJAutoProxy
    @ComponentScan(basePackageClasses={UserManager.class, SecurityHandler.class})
    public class Config {
    }
    

    测试 IoCTest.java

    package win.iot4yj.spring.test;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    import win.iot4yj.spring.manager.UserManager;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes=win.iot4yj.spring.config.Config.class)
    public class IoCTest {
        
        @Autowired
        private UserManager userManager;
    
        @Test
        public void test01() {
            userManager.addUser("张三", "123");
        }
    }
    

    说明:这里我们使用的是前置通知。会在添加用户之前进行安全性检查。

    二、环绕通知

    下面看环绕通知,没有给出的代码和之前一样。

    SecurityHandler.java

    package win.iot4yj.spring.aspect;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    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;
    
    /**
     * 
     * @author yj
     * 这个类就是一个切面
     */
    
    @Aspect
    @Component
    public class SecurityHandler {
        
        //定义一个切点,只是相当于一个标识。即匹配所有add开头的方法,参数和返回值任意。而allAddMethod方法不能有返回值
        @Pointcut("execution(* add*(..))")
        private void allAddMethod(){}
        
        
        //这个方法就相当于一个通知,标识在哪个切入点织入
        @Around("allAddMethod()")
        private void checkSevurity(ProceedingJoinPoint jp){
            System.out.println("-------安全性检查之前-------");
            try {
                jp.proceed();//调用被通知的方法
            } catch (Throwable e) {
                e.printStackTrace();
            }
            System.out.println("-------安全性检查之后-------");
        }
    }
    

    三、传递参数

    可以从之前的测试代码中看到,添加用户肯定是传递了用户名和密码的,这里我们将其传递到通知中去。

    SecurityHandler.java

    package win.iot4yj.spring.aspect;
    import org.aspectj.lang.ProceedingJoinPoint;
    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;
    /**
     * 
     * @author yj
     * 这个类就是一个切面
     */
    
    @Aspect
    @Component
    public class SecurityHandler {
        
        //定义一个切点,只是相当于一个标识。即匹配所有add开头的方法,参数和返回值任意。而allAddMethod方法不能有返回值
        @Pointcut("execution(* add*(..)) && args(username, password)")
        private void allAddMethod(String username, String password){}
        
        //这个方法就相当于一个通知,标识在哪个切入点织入
        @Around("allAddMethod(username, password)")
        private void checkSevurity(ProceedingJoinPoint jp, String username, String password){
            System.out.println("-------安全性检查之前-------");
            try {
                jp.proceed();
            } catch (Throwable e) {
                e.printStackTrace();
            }
            System.out.println("用户名: " + username + ", 密码: " + password);
            System.out.println("-------安全性检查之后-------");
        }
    }
    

    说明:这里要注意的是一定要使用args(username, password)进行标识,这标明相关的参数也会传递到通知中去。

    四、引入新功能

    这里首先定义要引入的新功能的类和接口

    package win.iot4yj.spring.manager;
    public interface NewFun {
        public void newFunction();
    }
    
    package win.iot4yj.spring.manager;
    import org.springframework.stereotype.Component;
    
    @Component
    public class NewFunImpl implements NewFun {
    
        @Override
        public void newFunction() {
            System.out.println("-----引入的新功能-----");
        }
    }
    

    切面 SecurityHandler.java

    package win.iot4yj.spring.aspect;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.DeclareParents;
    import org.aspectj.lang.annotation.Pointcut;
    import org.springframework.stereotype.Component;
    import win.iot4yj.spring.manager.NewFun;
    import win.iot4yj.spring.manager.NewFunImpl;
    /**
     * @author yj
     * 这个类就是一个切面
     */
    @Aspect
    @Component
    public class SecurityHandler {
        
        @DeclareParents(value = "win.iot4yj.spring.manager.UserManager+",
                        defaultImpl = NewFunImpl.class)
        public static NewFun n;
        
        //定义一个切点,只是相当于一个标识。即匹配所有add开头的方法,参数和返回值任意。而allAddMethod方法不能有返回值
        @Pointcut("execution(* add*(..)) && args(username, password)")
        private void allAddMethod(String username, String password){}
        
        //这个方法就相当于一个通知,标识在哪个切入点织入
        @Around("allAddMethod(username, password)")
        private void checkSevurity(ProceedingJoinPoint jp, String username, String password){
            System.out.println("-------安全性检查之前-------");
            try {
                jp.proceed();
            } catch (Throwable e) {
                e.printStackTrace();
            }
            System.out.println("用户名: " + username + ", 密码: " + password);
            System.out.println("-------安全性检查之后-------");
        }
    }
    

    说明:相对于之前的代码,这里添加了引入新功能的配置。具体说明参考前一小节文章。

    测试 IoCTest.java

    package win.iot4yj.spring.test;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.ApplicationContext;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    import win.iot4yj.spring.manager.NewFun;
    import win.iot4yj.spring.manager.UserManager;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes=win.iot4yj.spring.config.Config.class)
    public class IoCTest {
        
        @Autowired
        private UserManager userManager;
        
        @Autowired
        ApplicationContext applicationContext;
    
        @Test
        public void test01() {
            userManager.addUser("张三", "123");
            NewFun newFun = (NewFun) applicationContext.getBean("userManager");
            newFun.newFunction();
        }
    }
    

    说明:这里首先自动注入了应用上下文类ApplicationContextspring中很多类,如上下文类、环境类Environment类都可以这样获得。而其实通过ApplicationContext就可以获得应用中已存在的bean,所以这里的UserManager bean自动注入可以省略。此时就可以使用新引入的功能了。

    相关文章

      网友评论

          本文标题:12、面向切面的Spring(补)(spring笔记)

          本文链接:https://www.haomeiwen.com/subject/vdfdxxtx.html