博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
spring AOP面向切面编程学习笔记
阅读量:6705 次
发布时间:2019-06-25

本文共 8667 字,大约阅读时间需要 28 分钟。

一、面向切面编程简介:

在调用某些类的方法时,要在方法执行前或后进行预处理或后处理;预处理或后处理的操作被封装在另一个类中。如图中,UserService类在执行addUser()或updateUser方法前开启事务,执行完后要提交事务;而几乎所有数据库操作都是如此,那么就可以将事务操作的方法提取出封装到一个类里。然后再利用代理类进行处理(目标类方法增强),返回代理类对象

二、AOP相关术语

Target:目标类,需要被增强的类。

JoinPoint:连接点,目标类上需要被增强的方法。(这些方法可以被增强,也可能不增强)。

PointCut:切入点,被增强的连接点(已经增强了)。切入点术语特殊的连接点

Advice:增强/通知,增强的方法。

weaving:织入,将切入点和通知结合,生成代理类过程。

Proxy:代理类。

Aspect:切面,切入点和通知结合形成的面

三、JDK动态代理模拟AOP

1、项目结构(接口+目标类+切面类+代理类+测试类)

2、新建接口UserService

package hjp.springAOP.jdkProxy;public interface UserService {    void addUser();    void updateUser();}
UserService

3、新建目标类UserServiceImpl,并实现接口UserService

package hjp.springAOP.jdkProxy;public class UserServiceImpl implements UserService {    @Override    public void addUser() {        // TODO Auto-generated method stub        System.out.println("jdk add user");    }    @Override    public void updateUser() {        // TODO Auto-generated method stub        System.out.println("jdk update user");    }}
UserServiceImpl

4、新建切面类MyAspect

package hjp.springAOP.jdkProxy;/** * 切面类,用于存放增强 *  * @author JiaPeng * */public class MyAspect {    public void beafore() {        System.out.println("before");    }    public void after() {        System.out.println("after");    }}
MyAspect

5、新建代理类MyFactory

package hjp.springAOP.jdkProxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;/** * 工厂生成代理类,目的:将目标类(切入点)和切面类(通知)结合。 *  * @author JiaPeng * */public class MyFactory {    public static UserService createService() {        // 创建目标类        final UserService userService = new UserServiceImpl();        // 创建切面类        final MyAspect myAspect = new MyAspect();        // 使用jdk动态代理,生成代理类        // 第一个参数是,当前类下的类加载器,第二个参数是目标类所继承的接口数组,第三个参数是匿名内部类        // 匿名内部类也就是没有名字的内部类;正因为没有名字,所以匿名内部类只能使用一次,它通常用来简化代码编写;但使用匿名内部类还有个前提条件:必须继承一个父类或实现一个接口        UserService proxyService = (UserService) Proxy.newProxyInstance(MyFactory.class.getClassLoader(),                userService.getClass().getInterfaces(), new InvocationHandler() {                    // 代理类每一个方法执行时,都将调用处理类的invoke方法                    @Override                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {                        // TODO Auto-generated method stub                        // 执行前通知                        myAspect.beafore();                        // 执行目标类的相应方法                        Object obj = method.invoke(userService, args);                        // 执行后通知                        myAspect.after();                        return obj;                    }                });        return proxyService;    }}
代理类

6、新建测试类

package hjp.springAOP.jdkProxy;import org.junit.Test;public class TestApp {    @Test    public void demo1() {        UserService userService = MyFactory.createService();        userService.addUser();        userService.updateUser();    }}
测试类

四、CGLIB模拟AOP

cglib 字节码增强工具,一般框架都使用。只要有类就可以增强

1、项目结构(cglib的jar包已被spring打包好了,所以添加了spring的主要jar包就可以了)

2、新建目标类UserServiceImpl,没有接口

package hjp.springAOP.cglibProxy;public class UserServiceImpl {    public void addUser() {        System.out.println("cglib add user");    }    public void updateUser() {        System.out.println("cglib update user");    }}
UserServiceImpl

3、新建切面类

package hjp.springAOP.cglibProxy;/** * 切面类,用于存放增强 *  * @author JiaPeng * */public class MyAspect {    public void beafore() {        System.out.println("before");    }    public void after() {        System.out.println("after");    }}
切面类

4、新建代理类

package hjp.springAOP.cglibProxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import org.eclipse.jdt.internal.compiler.classfmt.FieldInfoWithAnnotation;import org.springframework.cglib.proxy.Enhancer;import org.springframework.cglib.proxy.MethodInterceptor;import org.springframework.cglib.proxy.MethodProxy;/** * 工厂生成代理类,目的:将目标类(切入点)和切面类(通知)结合。 *  * @author JiaPeng * */public class MyFactory {    public static UserServiceImpl createService() {        // 创建目标类        final UserServiceImpl userServiceImpl = new UserServiceImpl();        // 创建切面类        final MyAspect myAspect = new MyAspect();        // 使用cglib创建代理类,其实现方式就是在cglib运行时,动态创建目标类子类(该子类就是代理类,Java动态代理是基于接口或父类的)        // 创建核心类        Enhancer enhancer = new Enhancer();        // 设置父类        enhancer.setSuperclass(userServiceImpl.getClass());        // 代理类方法将调用回调函数,等效JDK InvocationHandler        // 接口Callback,子接口MethodInterceptor对方法进行增强        enhancer.setCallback(new MethodInterceptor() {            @Override            // 前三个参数与jdk动态代理invoke相同            // 第四个参数是方法代理            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy)                    throws Throwable {                // TODO Auto-generated method stub                // 切面类的前通知                myAspect.beafore();                // 目标方法                //Object object = method.invoke(userServiceImpl, args);                Object object = methodProxy.invokeSuper(proxy, args);//执行代理类(子类)父类方法(父类就是目标类),效果和上面的一样                // 切面类后通知                myAspect.after();                return object;            }        });        // 创建代理类        return (UserServiceImpl) enhancer.create();    }}
代理类

5、新建测试类

package hjp.springAOP.cglibProxy;import org.junit.Test;public class TestApp {    @Test    public void demo1() {        UserServiceImpl userService = MyFactory.createService();        userService.addUser();        userService.updateUser();    }}
测试类

 五、利用spring工厂bean,半自动化模拟AOP

使用spring提供FactoryBean创建代理对象,手动的获取代理对象。生成代理需要应用增强(通知),通知需要确定方法名称。spring规范规定通知类型从而确定方法名称。

AOP联盟五种通知类型,spring对AOP联盟进行支持。

  前置通知:org.springframework.aop.MethodBeforeAdvice 在目标方法执行前实施增强

  后置通知:org.springframework.aop.AfterReturningAdvice 在目标方法执行后实施增强

  环绕通知:org.aopalliance.intercept.MethodInterceptor 在目标方法执行前后实施增强

  异常抛出通知:org.springframework.aop.ThrowsAdvice 在方法抛出异常后实施增强

  引介通知:org.springframework.aop.Introductioninterceptor 在目标类中添加一些新的方法和属性

环绕通知可以模拟其他通知类型,如:

try{

前置

//必须手动执行目标方法

后置

}catch{

//异常抛出

}

1、项目结构:(新加AOP联盟的jar包和spring对AOP依赖的jar包)

2、接口UserService及其实现类UserServiceImpl同上面一样

3、切面类MyAspect不一样了,需要继承接口MethodInterceptor并实现其方法,代码如下:

package hjp.springAOP.springFactoryBeanProxy;import org.aopalliance.intercept.MethodInterceptor;import org.aopalliance.intercept.MethodInvocation;/** * 切面类,用于存放通知(增强),使用的AOP联盟规范,必须实现接口,从而确定方法名称(即,spring如何执行通知) *  * @author JiaPeng * */public class MyAspect implements MethodInterceptor {    @Override    public Object invoke(MethodInvocation methodInvocation) throws Throwable {        // TODO Auto-generated method stub        System.out.println("前");        //环绕通知,必须手动的执行目标方法        Object obj=methodInvocation.proceed();                System.out.println("后");        return obj;    }    }
切面类

4、测试类代码如下:

package hjp.springAOP.springFactoryBeanProxy;import org.junit.Test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class TestApp {    @Test    public void demo1() {        String xmlPath="hjp/springAOP/springFactoryBeanProxy/beans.xml";        ApplicationContext applicationContext=new ClassPathXmlApplicationContext(xmlPath);        UserService userService = (UserService)applicationContext.getBean("proxyServiceId");        userService.addUser();        userService.updateUser();    }}
测试类

5、新建beans.xml配置文件,里面有注解,不再赘述,注意配置中可以设置是否使用cglib代理

配置文件

 六、传统springAOP

1、项目结构(较上面中的引用,新增了aspectj的jar包)

2、接口UserService及其实现类UserServiceImpl如上,MyAspect切面类也是如上实现接口MethodInterceptor

3、beans.xml配置文件,注意要加xsd引用(命名空间xmlns:aop="http://www.springframework.org/schema/aop;引用地址:http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd

配置文件

4、测试类代码:

package hjp.springAOP.springAOP;import org.junit.Test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class TestApp {    @Test    public void demo1() {        String xmlPath="hjp/springAOP/springAOP/beans.xml";        ApplicationContext applicationContext=new ClassPathXmlApplicationContext(xmlPath);        UserService userService = (UserService)applicationContext.getBean("userServiceId");        userService.addUser();        userService.updateUser();    }}
测试类

 

转载地址:http://lqflo.baihongyu.com/

你可能感兴趣的文章
如何从零起步开发一款App
查看>>
iptables学习笔记
查看>>
scapy模块实现arp扫描,断网×××
查看>>
PHP-5.5.10+Apache httpd-2.4.9在Windows系统下配置实战
查看>>
oracle 表之间的连接;内连接 ,左连接 右连接
查看>>
2.windows安装mongodb企业版
查看>>
开源中国 OsChina Android 客户端源码分析(4)自定义对话框
查看>>
面向对象编程
查看>>
日常运维(一)
查看>>
inherited_resources 简介 1
查看>>
磁盘格式化、磁盘挂载、手动增加swap空间
查看>>
链表的遍历-奇数结点个数
查看>>
linux
查看>>
Windows开启SNMP服务----Win7
查看>>
springcloud(三):服务提供与调用
查看>>
在ECSHOP后台会员列表中显示最后登录时间
查看>>
ios第四天
查看>>
两天 写出简易数据库管理程序
查看>>
JAVA设计原则之依赖倒置原则
查看>>
SVN服务器从Windows迁移到LInux
查看>>