1、AOP思想

面向切面编程,采取横向抽取的方式,取代了纵向继承体系代码的重复性。底层采用代理的机制进行实现,是面向对象编程的延续,使得业务的耦合性降低,提高了程序的可重用性

应用:

事务管理、性能监控、安全检查、缓存、日志等

(1)在解决中文乱码的应用:

一般情况下如果在Servlet中要解决中文乱码问题需要在每一个Servlet中书写解决乱码的代码,但是,在运用了过滤器之后,就不再需要每一个Servlet中都写解决乱码的函数,减少了代码量。

AOP思想又叫做“面向切面编程”,过滤器就是面向每一个Servlet的,每一个Servlet都需要执行过滤器。

(2)动态代理:

代理类的那部分代码被固定下来了,不会因为业务的增加而逐渐庞大。

(3)拦截器:

不需要在每一个Action中书写拦截器的代码,只需要在Action需要的时候在配置文件中将相应的拦截器配置进去即可。

2、Spring中的AOP

Spring能够为容器中管理的对象生成动态代理对象。这样做是有好处的,如果把登录功能写在每一个业务中当需要修改代码的时候,就需要对每一个业务进行修改,但是,如果把登录功能抽取出来形成独立的模块,问题就迎刃而解了。

3、Spring实现aop的原理

(1)动态代理(优先使用):被代理对象必须要实现接口,才能产生代理对象,如果没有接口将不能实现动态代理。

假如登录需要分为登录前、登录、登录后三部分,也就是说登录部分是相同的代码,而登录前和登录后的代码根据用户的不同进行不同的操作,那么,登录接口可以这样写:

public class LoginService {
public void userLogin(){
System.out.println("登录前的操作");
System.out.println("登录");
System.out.println("登录后的操作");
}
public void managerLogin(){
System.out.println("登录前的操作");
System.out.println("登录");
System.out.println("登录后的操作");
}
}

这样写的话不仅会造成代码的冗余,而且,如果要修改登录的代码的话两个都要分别作出修改,可以使用动态代理的方式将公共部分抽取出来:

定义登录接口:

public interface LoginService {
public void userLogin();
public void managerLogin();
}

定义接口的实现类:

public class LoginProxyImp implements LoginService{
public void userLogin(){
System.out.println("普通用户登录前的操作"); }
public void managerLogin(){
System.out.println("管理员登录前的操作"); }
}

创建代理类:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class LoginProxy implements InvocationHandler {
private LoginService ls;
public LoginProxy(LoginService ls) {
super();
this.ls = ls;
}
public LoginService getloginProxy(){
LoginService loginService= (LoginService) Proxy.newProxyInstance(LoginService.class.getClassLoader(),//创建接口实例
LoginProxyImp.class.getInterfaces(),//与目标对象有相同的类加载器
this); //被代理的类所实现的接口(可以是多个)
return loginService;//产生代理对象
}
@Override
public Object invoke(Object proxy, Method method, Object[] arg2) throws Throwable {
Object invoke=method.invoke(ls,arg2);
System.out.println("登录");//抽取出来的公共部分
return invoke;
}
}

测试类:

public class TestProxy {
public static void main(String [] args){
LoginService loginService=new LoginProxyImp();
LoginProxy loginProxy=new LoginProxy(loginService);
LoginService loginService1=loginProxy.getloginProxy();
loginService1.userLogin();
}
}

(2)cglib技术:可以对任何类生成代理对象,原理是对目标对象进行继承代理,如果该目标对象被final修饰,将无法使用cglib技术

登录接口:

public interface LoginService {
public void userLogin();
public void managerLogin();
}

接口的实现类:

public class LoginProxyImp implements LoginService{
public void userLogin(){
System.out.println("普通用户登录前的操作"); }
public void managerLogin(){
System.out.println("管理员登录前的操作"); }
}

创建代理类:

public class LoginProxy implements MethodInterceptor {

    public LoginService getLoginServiceProxy(){
Enhancer enhancer=new Enhancer();//帮我们生成代理对象
enhancer.setSuperclass(LoginProxyImp.class);//设置对谁进行代理,即确定父类
enhancer.setCallback(this);//代理要做什么,即设定回调函数
LoginService loginService=(LoginService) enhancer.create();//创建代理对象
return loginService;
} @Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//前三个参数和jdk方式的代理相同
Object invokeSuper = methodProxy.invokeSuper(o,objects);
return invokeSuper;
}
}

测试类:

public class TestProxy {
public static void main(String [] args){
LoginProxy loginProxy=new LoginProxy();
LoginService loginService=loginProxy.getLoginServiceProxy();
loginService.userLogin();
System.out.println("登录");
}
}

这种方式是代理对象继承了被代理对象。

4、aop中的名词

(1)连接点(Joinpoint):目标对象中可以增强的的方法

public class LoginProxyImp implements LoginService{
public void userLogin(){
System.out.println("普通用户登录前的操作"); }
public void managerLogin(){
System.out.println("管理员登录前的操作"); }
}

该方法还可以通过动态代理增加登录的功能。

(2)切入点(PointCut):目标对象已经增强的方法

    public void userLogin(){
System.out.println("普通用户登录前的操作"); }
public void managerLogin(){
System.out.println("管理员登录前的操作"); }

例如:上述两个登录的方法通过动态代理已经增强的方法。

(3)advice(通知 / 增强):Spring中一共有五种通知类型

  public Object invoke(Object proxy, Method method, Object[] arg2) throws Throwable {
Object invoke=method.invoke(ls,arg2);
System.out.println("登录");//抽取出来的公共部分
return invoke;
}

加入了登录的功能,这部分代码是advice。

(4)Target(目标对象):

被代理的对象。

(5)weaving(织入):

将通知应用到切入点的形成代理类的过程。

(6)proxy(代理):

将通知织入到目标对象以后,形成代理对象

(7)切面(aspect):切入点加通知

5、Spring中的aop演示

(1)导包:

(2)对配置文件进行配置:

需要先导入aop约束:

(3)创建接口:

public interface LoginService {
public void userLogin();
public void managerLogin();
}

(4)创建目标对象:

public class LoginServiceImp {
public void userLogin(){
System.out.println("普通用户登录前的操作"); }
public void managerLogin(){
System.out.println("管理员登录前的操作"); }
}

(5)创建通知类:

public class LoginServiceImp {
public void userLogin(){
System.out.println("普通用户登录前的操作"); }
public void managerLogin(){
System.out.println("管理员登录前的操作"); }
}

(6)配置Spring的配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans" xmlns:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.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.xsd">
<bean name="loginserviceTarget" class="pers.zhb.test.LoginServiceImp"></bean><!--配置目标对象-->
<bean name="myadvice" class="pers.zhb.test.MyAdvice"></bean><!--配置通知对象-->
<aop:config>
<aop:pointcut expression="execution(* pers.zhb.test.LoginServiceImp.userLogin())" id="pointcut"/>
<aop:aspect ref="myadvice">
<aop:before method="before" pointcut-ref="pointcut"/>
<aop:after method="after" pointcut-ref="pointcut"/>
<aop:after-throwing method="afterException" pointcut-ref="pointcut"/>
<aop:around method="around" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config> </beans>

(1)配置目标对象,即被代理的对象。

(2)配置通知对象,即需要加入的那部分代码。

(3)将通知织入目标对象:需要先配置接入点,即:userLogin(),将通知对象加入目标对象。

好处:通过配置文件的形式实现aop的开发,我们就不需要手动书写动态代理的代码了,可以进行任何类的代理,不需要接口也可以。

6、使用注解完成Spring的aop配置

配置文件的书写:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans" xmlns:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.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.xsd">
<bean name="loginserviceTarget" class="pers.zhb.test.LoginServiceImp"></bean><!--配置目标对象-->
<bean name="myadvice" class="pers.zhb.test.MyAdvice"></bean><!--配置通知对象-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy><!--开启使用注解完成织入-->
</beans>

使用注解配置:

package pers.zhb.test;
//通知类,即用于增强目标对象的代码
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*; @Aspect//表示该类是一个通知类
public class MyAdvice {
@Before("execution(* pers.zhb.test.LoginServiceImp.userLogin())")//指定切入点(前置通知)
public void before(){
System.out.println("我是前置通知!");
}
@Around("execution(* pers.zhb.test.LoginServiceImp.userLogin())")
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("这是环绕通知之前的部分!");
Object process=proceedingJoinPoint.proceed();//环绕通知
System.out.println("这是环绕通知之后的部分!");
return process;
}
@AfterThrowing("execution(* pers.zhb.test.LoginServiceImp.userLogin())")
public void afterException(){
System.out.println("异常出现了!");
}
@After("execution(* pers.zhb.test.LoginServiceImp.userLogin())")
public void after(){
System.out.println("后置通知,出现异常也能被调用!");
}
@AfterReturning("execution(* pers.zhb.test.LoginServiceImp.userLogin())")
public void AfterReturning(){
System.out.println("我是后置通知,出现异常不会执行!!");
}
}

但是,用上面的方法配置的注解不利于修改,可以进行下面的配置:

package pers.zhb.test;
//通知类,即用于增强目标对象的代码
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*; @Aspect//表示该类是一个通知类
public class MyAdvice {
@Pointcut("execution(* pers.zhb.test.LoginServiceImp.userLogin())")
public void pc(){ }
@Before("MyAdvice.pc()")//指定切入点(前置通知)
public void before(){
System.out.println("我是前置通知!");
}
@Around("MyAdvice.pc()")
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("这是环绕通知之前的部分!");
Object process=proceedingJoinPoint.proceed();//环绕通知
System.out.println("这是环绕通知之后的部分!");
return process;
}
@AfterThrowing("MyAdvice.pc()")
public void afterException(){
System.out.println("异常出现了!");
}
@After("MyAdvice.pc()")
public void after(){
System.out.println("后置通知,出现异常也能被调用!");
}
@AfterReturning("execution(* pers.zhb.test.LoginServiceImp.userLogin())")
public void AfterReturning(){
System.out.println("我是后置通知,出现异常不会执行!!");
}
}

Spring的aop思想的更多相关文章

  1. [ SSH框架 ] Spring框架学习之二(Bean的管理和AOP思想)

    一.Spring的Bean管理(注解方式) 1.1 什么是注解 要使用注解方式实现Spring的Bean管理,首先要明白什么是注解.通俗地讲,注解就是代码里的特殊标记,使用注解可以完成相应功能. 注解 ...

  2. spring(二) AOP之AspectJ框架的使用

    前面讲解了spring的特性之一,IOC(控制反转),因为有了IOC,所以我们都不需要自己new对象了,想要什么,spring就给什么.而今天要学习spring的第二个重点,AOP.一篇讲解不完,所以 ...

  3. Spring框架AOP学习总结(下)

    目录 1. AOP 的概述 2. Spring 基于AspectJ 进行 AOP 的开发入门(XML 的方式): 3.Spring 基于AspectJ 进行 AOP 的开发入门(注解的方式): 4.S ...

  4. Spring框架学习之注解配置与AOP思想

         上篇我们介绍了Spring中有关高级依赖关系配置的内容,也可以调用任意方法的返回值作为属性注入的值,它解决了Spring配置文件的动态性不足的缺点.而本篇,我们将介绍Spring的又一大核心 ...

  5. Spring框架系列之AOP思想

    微信公众号:compassblog 欢迎关注.转发,互相学习,共同进步! 有任何问题,请后台留言联系! 1.AOP概述 (1).什么是 AOP AOP 为 Aspect Oriented Progra ...

  6. spring框架学习(四)AOP思想

    什么是AOP 为什么需要AOP 从Spring的角度看,AOP最大的用途就在于提供了事务管理的能力.事务管理就是一个关注点,你的正事就是去访问数据库,而你不想管事务(太烦),所以,Spring在你访问 ...

  7. spring框架中AOP思想与各种配置详解

    Spring中提供两种AOP支持:   1.基于代理的经典AOP   2.Aspectj注解配置AOP    首先我们先了解什么是AOP,AOP(Aspect Oriented Programming ...

  8. 【Spring Framework】Spring入门教程(五)AOP思想和动态代理

    本文主要讲解内容如下: Spring的核心之一 - AOP思想 (1) 代理模式- 动态代理 ① JDK的动态代理 (Java官方) ② CGLIB 第三方代理 AOP概述 什么是AOP(面向切面编程 ...

  9. 深入理解Spring AOP思想

    什么是AOP?AOP解决了什么问题? 在传统的开发模式中,以下层次的是非常常见的一种,业务层每一个方法都要有重复的事务代码 如何改善这个问题? AOP希望将A.B 这些分散在各个业务逻辑中的相同代码, ...

随机推荐

  1. .NET Core 3.1之深入源码理解HealthCheck(二)

    写在前面 前文讨论了HealthCheck的理论部分,本文将讨论有关HealthCheck的应用内容. 可以监视内存.磁盘和其他物理服务器资源的使用情况来了解是否处于正常状态. 运行状况检查可以测试应 ...

  2. 理解 RESTful API 设计规范

    RESTful是目前最流行的API设计规范,它是用于Web数据接口的设计.从字面可以看出,他是Rest式的接口,所以我们先了解下什么是Rest. REST与技术无关,它代表的是一种软件架构风格,RES ...

  3. 洛谷P1189 SEARCH 题解 迭代加深

    题目链接:https://www.luogu.com.cn/problem/P1189 题目大意: 给你一个 \(n \times m\) 的矩阵,其中有一些格子可以走,一些各自不能走,然后有一个点是 ...

  4. linux各目录及重要目录的详细介绍

    1 目录说明 根目录 (/) /bin bin是Binary的缩写, 这个目录存放着最经常使用的命令,比如ls,cat,mkdir等 /dev dev是Device(设备)的缩写, 该目录下存放的是L ...

  5. Atom + Texlive 配置 Latex 环境

    Atom + Texlive 配置 Latex 环境 步骤1: 安装TexliveTexlive点击 "Download" 下载,然后安装,等待安装完成即可 步骤2: 安装Atom ...

  6. 【转】ArcGIS Server 10.1 动态图层

    ArcGISServer将GIS资源以服务的方式发布,能够让更多的人在Web上浏览.使用.不过,诸如气象.环保等方面的信息是实时变化的,按照之前常规的方法,我们先要将最新获得的信息组织成地图文档后再对 ...

  7. UGUI ScrollView中显示模型和特效

    游戏开发中有时候会遇到在UI上显示模型和特效的需求,这次需要在ScrollView上显示.我们使用UGUI的Screen Space - Camera模式,修改模型和特效的layer使之显示在UI上面 ...

  8. Java工程师 基础+实战 完整路线图(详解版)

    Java工程师 基础+实战 完整路线图(详解版)   Java 基础 Java 是一门纯粹的面向对象的编程语言,所以除了基础语法之外,必须得弄懂它的 oop 特性:封装.继承.多态.此外还有泛型.反射 ...

  9. Spring--2.Spring之IOC--IOC容器的23个实验(1)

     实验1.IOC容器创建对象,并为属性赋值 Hello World:(通过各种方式给容器中注册对象(注册会员)) 以前是自己new对象,现在所有对象交给容器创建:给容器中注册组件 以后框架编写流程: ...

  10. cannot mount volume over existing file, file exists /var/lib/docker/overlay2/.../merged/usr/share/zoneinfo/UTC 解决

    问题产生原因: linux系统docker-compose.yml文件 放到 mac本启动发现启动报错 cannot mount volume over existing file, file exi ...