前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >「2020最新」Spring最易学习教程 3— 代理设计模式 Spring AOP 动态代理原理

「2020最新」Spring最易学习教程 3— 代理设计模式 Spring AOP 动态代理原理

原创
作者头像
鹿老师的Java笔记
修改2020-07-30 14:31:10
3490
修改2020-07-30 14:31:10
举报

0 复习

  1. FactoryBean技术(用于创建复杂对象) 复杂对象:底层不能直接通过new构造方法创建,通常需要若干步骤才能创建的对象。比如:Connection、SqlSession
    1. 编码 implements FactoryBean
    2. 配置 通过bean标签配置
  2. 配置文件
    1. import标签
    2. xsd使用规则
    3. 拆分jdbc.properties文件
  3. 概念总结 IOC和DI
  4. Spring整合Struts2 导入依赖:spring-web struts2-spring-plugin
    1. web.xml 在tomcat启动应用时,创建Spring工厂 <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
    2. Struts2从Spring工厂中获取Action applicationContext.xml bean标签配置action和service 注意: action需要多例 struts.xml <action name="路径" class="bean的id"></action>
  5. 注解开发 Component(Controller、Service、Repository)替换bean标签 Autowired替换property标签

Spring AOP

1 代理设计模式

1.1 解决的问题

image-20200602101013042
image-20200602101013042

image-20200602101013042

要不要在业务层中定义额外功能?

业务调用者的角度:需要,业务方法中需要使用这些额外功能 软件设计者的角度:不需要,定义后会造成代码的频繁修改

矛盾的解决方案:代理模式

1.2 代理模式

image-20200602102246281
image-20200602102246281

image-20200602102246281

矛盾:

房东不愿意提供额外功能(带看房,车接车送),因为麻烦 租客必须要使用这些额外功能

矛盾的解决方案:中介

中介代理了房东的出租房屋的方法,同时提供额外的功能。 房东无需亲自和租客打交道,节省时间。租客也可以享受完整的服务。

在程序中,Action(租客) 和 Serivce(房东) 的矛盾,也可以通过添加一个代理类解决。

1.3 静态代理

image-20200602103550535
image-20200602103550535

image-20200602103550535

实战:

接口:

代码语言:javascript
复制
public interface UserService {
    public boolean login(String username,String password);
    public void removeUser(Integer id);
}

原始实现类:

代码语言:javascript
复制
public class UserServiceImpl implements UserService {
    @Override
    public boolean login(String username, String password) {
        System.out.println("username = [" + username + "], password = [" + password + "]");
        return false;
    }

    @Override
    public void removeUser(Integer id) {
        System.out.println("id = [" + id + "]");
    }
}

代理实现类:

代码语言:javascript
复制
public class UserServiceProxy implements UserService {
    private UserService userService = new UserServiceImpl();
    @Override
    public boolean login(String username, String password) {
        System.out.println("开启事务");
        boolean result = userService.login(username,password);
        System.out.println("结束事务");
        return result;
    }

    @Override
    public void removeUser(Integer id) {
        System.out.println("开启事务");
        userService.removeUser(id);
        System.out.println("结束事务");
    }
}

使用者:

代码语言:javascript
复制
public class UserAction {
    private UserService userService = new UserServiceProxy();
    public String login(){
        userService.login("xiaohei", "123456");
        return "success";
    }
    public String removeUser(){
        userService.removeUser(1);
        return "success";
    }
}

2 Spring动态代理

静态代理的问题:

  1. 随着额外功能的增多,代理类数量随之增多,不利于管理
  2. 代理类冗余,存在多个代理类提供相同的功能

解决方案:动态代理

Spring动态代理:无需程序员手动编写代理类,只需要提供额外功能代码,然后由Spring框架自动的为原始类生成有增强功能的代理类。

好处:提高开发效率。

开发步骤:

额外引入以下2个依赖:spring-aop aspectjweaver

代码语言:javascript
复制
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>4.3.26.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.5</version>
</dependency>
  1. 创建原始类型对象 <bean id="标识" class="原始(目标)类全类名"></bean>
  2. 定义额外功能。实现Spring的特定接口 public class MyMethodBeforeAdvice implements MethodBeforeAdvice { @Override /* method: 原始类型中方法 args: 参数 target: 原始对象 */ public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println("before..."); } }
  3. 配置额外功能类 <!-- 配置功能增强类 --> <bean id="myBeforeAdvice" class="com.bcl.advice.MyMethodBeforeAdvice"/>
  4. 定义切入点:决定额外功能添加到哪个位置
  5. 组装 <aop:config> <!-- 定义切入点--> <aop:pointcut id="myPointCut" expression="execution(* com.bcl.service.*.*(..))"/> <!-- 组装 --> <aop:advisor advice-ref="myBeforeAdvice" pointcut-ref="myPointCut"/> </aop:config>

名词(术语)解释:

  • 原始类(目标类):提供核心功能的类
  • 原始方法(目标方法):原始类中没有加入额外功能的方法
  • 额外功能(增强):用于增强原始方法的代码

3 Spring动态代理的实现流程

image-20200602114248141
image-20200602114248141

image-20200602114248141

4 增强(Advice)

4.1 前置增强

增强会在目标方法前执行,实现接口 MethodBeforeAdvice

代码语言:javascript
复制
public class MyMethodBeforeAdvice implements MethodBeforeAdvice {
    @Override
    /*
        method: 原始方法
        args: 调用方法时的实参列表
        target: 原始对象
     */
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("method = [" + method + "], args = [" + Arrays.toString(args) + "], target = [" + target + "]");
        System.out.println("target.getClass() = " + target.getClass());
        System.out.println("前置增强");
    }
}

4.2 后置增强

增强代码会在目标方法正常return后执行,实现接口 AfterReturningAdvice

代码语言:javascript
复制
public class MyAfterReturningAdvice implements AfterReturningAdvice {
    /*
        returnValue: 原始方法正常结束后的返回值
        method: 原始方法
        args: 实参列表
        target: 原始对象
     */
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("后置增强");
    }
}

4.3 异常增强

增强代码在目标方法发生异常时执行,实现接口 ThrowsAdvice

代码语言:javascript
复制
public class MyThrowsAdvice implements ThrowsAdvice {
    /*
        method: 原始方法
        args: 实参列表
        target: 原始对象
        throwable: 原始方法运行时的异常
     */
    public void afterThrowing(Method method, Object[] args,Object target, Throwable throwable){
        System.out.println("异常增强");
    }
}

4.4 环绕增强

增强代码在目标方法前后以及异常时都可以执行,实现接口 MethodInterceptor

image-20200602144422389
image-20200602144422389

image-20200602144422389

代码语言:javascript
复制
public class MyRoundAdvice implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation pj) throws Throwable {
        System.out.println("前置增强");

        Object result = null;
        try {
            //放行:调用原始方法
            result = pj.proceed();

            System.out.println("后置增强");
        }catch(Exception e){
            System.out.println("异常增强");
            throw e;
        }finally{
            System.out.println("最终增强");
        }
        return result;
    }
}

5 切入点详解

切入点:需要做功能增强处理的位置,可以通过切入点表达式描述。

5.1 execution表达式[重点]

image-20200602150619051
image-20200602150619051

image-20200602150619051

实战中,使用 execution(* com.bcl.service.*.*(..)) 添加额外功能。

5.2 args表达式

用来匹配特定参数的方法。

args(参数列表)

5.3 within表达式

用来匹配特定的类,根据类名匹配。

within(类名表达式)

5.4 @annotation表达式

@annotation(注解类型),通过特定的注解来匹配类。

  1. 自定义一个注解 public @interface MyAnnotation { }
  2. 使用自定义注解描述方法(实现类中的方法) public class UserServiceImpl implements UserService { @Override @MyAnnotation public boolean login(String username, String password) { System.out.println("username = [" + username + "], password = [" + password + "]"); return false; } @Override public void removeUser(Integer id) { System.out.println("id = [" + id + "]"); //int i = 10/0; } }
  3. 切入点配置为 @annotation(自定义注解类型) <aop:pointcut id="myPointCut" expression="@annotation(com.bcl.annotation.MyAnnotation)"/>

5.5 表达式的运算符

表达式之间可用过 and or not运算。

6 Spring AOP

AOP(Aspect Oriented Programming)面向切面编程。

OOP(Object Oriented Programming)面向对象编程。

6.1 OOP(面向对象编程)

面向对象编程以对象为单位进行编程,抽取共性方法,通过继承重用这些方法。

image-20200602153645027
image-20200602153645027

image-20200602153645027

6.2 Spring AOP

AOP为了解决程序中零散的共性代码的复用问题,是OOP有力补充。

  1. 增强:共性代码,额外功能。比如:事务、性能分析
  2. 切入点:添加额外功能的方法的位置
  3. 织入(编织):将增强添加到切入点的过程
  4. 切面:在切点织入增强代码后形成的一个几何平面的概念
image-20200602154757972
image-20200602154757972

image-20200602154757972

面向切面编程的要素:增强、切点和织入

面向切面编程的作用:灵活的以非侵入的方式(非耦合式)为现有的方法增强功能。

Spring切面编程的步骤:

  1. 配置原始类型对象
  2. 定义额外功能(增强)
  3. 配置增强类
  4. 定义切入点
  5. 编织

7 数据库中事务的隔离级别

事务的隔离级别:事务并发执行时,微观上多个执行时间相近的事务相互影响的问题。

标准的隔离级别4种:

隔离级别

特点

问题

READ_UNCOMMITTED

可以读取到未提交的事务

脏读

READ_COMMITTED

只能读到已经提交的事务

不可重复读

REPEATABLE_READ

同1个事务中读取到数据始终一致

幻影读

SERIALIZABLE

序列化读,不允许并发操作

性能差

Oracle数据库,只支持2种:READ——COMMITTEDSERIALIZABLE ,MySQL支持4种。

MySQL隔离级别的演示:

  1. 确认MySQL的存储引擎 show engines;
  2. 查看隔离级别 select @@session.tx_isolation;
  3. 设置隔离级别 set @@session.tx_isolation=0 | 1 | 2 | 3
  4. 开启事务 begin;
  5. 结束事务 commit; rollback;

「❤️ 帅气的你又来看了我」

如果你觉得这篇内容对你挺有有帮助的话:

  1. 点赞支持下吧,让更多的人也能看到这篇内容(收藏不点赞,都是耍流氓 -_-)
  2. 欢迎在留言区与我分享你的想法,也欢迎你在留言区记录你的思考过程。
  3. 觉得不错的话,也可以关注 编程鹿 的个人公众号看更多文章和讲解视频(感谢大家的鼓励与支持🌹🌹🌹)

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 0 复习
  • Spring AOP
  • 1 代理设计模式
    • 1.1 解决的问题
      • 1.2 代理模式
        • 1.3 静态代理
        • 2 Spring动态代理
        • 3 Spring动态代理的实现流程
        • 4 增强(Advice)
          • 4.1 前置增强
            • 4.2 后置增强
              • 4.3 异常增强
                • 4.4 环绕增强
                • 5 切入点详解
                  • 5.1 execution表达式[重点]
                    • 5.2 args表达式
                      • 5.3 within表达式
                        • 5.4 @annotation表达式
                          • 5.5 表达式的运算符
                          • 6 Spring AOP
                            • 6.1 OOP(面向对象编程)
                              • 6.2 Spring AOP
                              • 7 数据库中事务的隔离级别
                              • 「❤️ 帅气的你又来看了我」
                              相关产品与服务
                              云数据库 MySQL
                              腾讯云数据库 MySQL(TencentDB for MySQL)为用户提供安全可靠,性能卓越、易于维护的企业级云数据库服务。其具备6大企业级特性,包括企业级定制内核、企业级高可用、企业级高可靠、企业级安全、企业级扩展以及企业级智能运维。通过使用腾讯云数据库 MySQL,可实现分钟级别的数据库部署、弹性扩展以及全自动化的运维管理,不仅经济实惠,而且稳定可靠,易于运维。
                              领券
                              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档