静态代理

缺点:一个真实角色就会产生一个代理角色,代码量会翻倍!

场景:要在写好的实现方法上加入日志功能(公共功能),不要修改原代码

1:原代码

业务接口:

package com.spring;

public interface UserService {

    public void addUser(String id);

    public void delUser(String id);

}

业务实现(真实角色):

package com.spring;

public class UserServiceImpl implements UserService {
@Override
public void addUser(String id) {
System.out.println("添加了一个用户");
} @Override
public void delUser(String id) {
System.out.println("删除了一个用户");
} }

实例化对象:

<bean id="userService" class="com.spring.UserServiceImpl"></bean>

测试:

@Test
public void test04(){
//获取容器
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
//获取bean
UserServiceImpl userService = applicationContext.getBean("userService", UserServiceImpl.class);
userService.addUser("1001");
}

2:增加日志功能(代理实现)

增加一个代理类,实现业务接口:(因为代理角色要代理实现真实角色同样的业务)

1:要在代理类中,定义真实角色 并且注入真实角色

2:调用真实角色的业务,并插入代理角色自己的附属业务

package com.spring;

/*代理类*/
package com.spring; /*代理类*/
public class UserServiceProxy implements UserService{
/*代理角色要代理真实角色*/
UserServiceImpl userService; /*给真实角色,添加set方法*/
public void setUserService(UserServiceImpl userService) {
this.userService = userService;
} @Override
public void addUser(String id) {
this.log("add");
userService.addUser(id);
} @Override
public void delUser(String id) {
this.log("del");
userService.delUser(id);
} /*代理角色的附属业务 日志功能*/
public void log(String msg){
System.out.println("执行了"+msg+"操作");
}
}

实例化对象:

<!--实例化真实角色-->
<bean id="userService" class="com.spring.UserServiceImpl"></bean> <!--实例化代理角色-->
<bean id="userServiceProxy" class="com.spring.UserServiceProxy">
<!--注入真实角色-->
<property name="userService" ref="userService"></property>
</bean>

测试:

@Test
public void test05(){
//获取容器
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
//获取代理bean
UserServiceProxy userServiceProxy = applicationContext.getBean("userServiceProxy", UserServiceProxy.class);
userServiceProxy.addUser(“1001”);
}

打印结果:

执行了add操作
添加了一个用户

动态代理

通过反射机制,解决静态代理的缺点;动态代理的代理类是自动生成的;基于JDK的接口实现

invocationhandler:接口 实现invoke方法

proxy:动态代理类

package com.spring;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; /*动态代理类要实现InvocationHandler接口*/
public class UserServiceDynamicProxy implements InvocationHandler { /*代理角色要代理真实角色*/
UserServiceImpl userService; /*给真实角色,添加set方法*/
public void setUserService(UserServiceImpl userService) {
this.userService = userService;
} /*生成并得到代理类
* 1:classloader:
* 2:真实角色:根据不同的真实角色 做修改
* 3:InvocationHandler
* return : 业务接口
* */
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(), userService.getClass().getInterfaces(), this);
}
/*自动处理代理实例 并返回结果*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //调用附属业务
this.log(method.getName());
//获取参数
String id = args[0].toString();
System.out.println("参数为:"+ id); //相当于执行业务方法
Object result = method.invoke(userService,args);
//返回业务执行结果
return result;
} /*代理角色的附属业务 日志功能*/
public void log(String msg){
System.out.println("执行了"+msg+"操作");
}
}

实例化对象:

<!--实例化真实角色-->
<bean id="userService" class="com.spring.UserServiceImpl"></bean> <!--实例化代理角色-->
<bean id="userServiceDynamicProxy" class="com.spring.UserServiceDynamicProxy">
<!--注入真实角色-->
<property name="userService" ref="userService"></property>
</bean>

测试:

@Test
public void test06(){
//获取容器
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
//获取动态代理bean
UserServiceDynamicProxy userServiceDynamicProxy = applicationContext.getBean("userServiceDynamicProxy", UserServiceDynamicProxy.class);
/*得到这个代理类 返回业务接口*/
UserService proxy = (UserService) userServiceDynamicProxy.getProxy();
//调用业务方法
proxy.addUser("1001");
}

打印结果:

执行了addUser操作
参数为:1001
添加了一个用户

面向切面

面向切面主要应用于日志、安全、缓存、事务管理

切面:切入的类,比如 log类

通知:切入的具体方法,比如 log里面的一个方法

目标:在哪切入

切入点:什么时候执行,比如业务方法执行前或者执行后

面向切面环境配置:

1:导入AOP命名空间:

<?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"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd"> </beans>

2:导入依赖包:

<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>

一、Spring API实现AOP

定义业务接口:

package com.spring;

public interface UserService {

    public void addUser(String id);

    public void delUser(String id);
}

实现业务接口:

package com.spring;

public class UserServiceImpl implements UserService {
@Override
public void addUser(String id) {
System.out.println("添加了一个用户");
} @Override
public void delUser(String id) {
System.out.println("删除了一个用户");
} }

定义切面和通知(类和方法):

前置通知:MethodBeforeAdvice

package com.spring.log;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class BeforeLog implements MethodBeforeAdvice {

    @Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("业务前日志被调用 信息为"+o.getClass().getName()+"类的"+method.getName()+"的方法");
}
}

后置通知:AfterReturningAdvice

package com.spring.log;

import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method; public class AfterLog implements AfterReturningAdvice {
@Override
public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
System.out.println("业务后日志被调用 信息为:执行了"+method.getName()+" 返回信息为"+o);
}
}

实例化对象以及配置AOP:

<bean id="userService" class="com.spring.UserServiceImpl"></bean>

<bean id="beforeLog" class="com.spring.log.BeforeLog"></bean>
<bean id="afterLog" class="com.spring.log.AfterLog"></bean> <!--配置AOP面向切面-->
<aop:config>
<!--定义切入点-->
<aop:pointcut id="point" expression="execution(* com.spring.UserServiceImpl.*(..))"></aop:pointcut>
<!--执行切入 以及关联切入点-->
<aop:advisor advice-ref="beforeLog" pointcut-ref="point"></aop:advisor>
<aop:advisor advice-ref="afterLog" pointcut-ref="point"></aop:advisor>
</aop:config>

测试:

@Test
public void test04(){
//获取容器
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
//动态代理 代理的是接口 所以要返回一个接口
UserService userService = applicationContext.getBean("userService", UserService.class);
userService.addUser("1001");
}

打印结果:

业务前日志被调用 信息为com.spring.UserServiceImpl类的addUser的方法
添加了一个用户
业务后日志被调用 信息为:执行了addUser 返回信息为null

二、自定义类实现AOP

业务接口和实现类基于【Spring API实现AOP】

定义一个自定也切面和通知:

package com.spring.log;

public class MyLog {

    public void before(){
System.out.println("业务前调用");
} public void after(){
System.out.println("业务后调用");
}
}

实例化对象以及配置AOP:

<!--配置AOP面向切面-->
<aop:config>
<!--自定义切面-->
<aop:aspect ref="myLog">
<!--定义切入点-->
<aop:pointcut id="point" expression="execution(* com.spring.UserServiceImpl.*(..))"></aop:pointcut>
<!--执行切入 以及关联切入点-->
<aop:before method="before" pointcut-ref="point"></aop:before>
<aop:after method="after" pointcut-ref="point"></aop:after>
</aop:aspect>
</aop:config>

测试:

测试方法基于【Spring API实现AOP】

打印结果:

业务前调用
添加了一个用户
业务后调用

三、自定义类实现AOP

业务接口和实现类基于【Spring API实现AOP】

定义一个自定也切面和通知:

package com.spring.log;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before; @Aspect/*标记这是一个切面*/
public class MyLog { /*定义切入点*/
@Before("execution(* com.spring.UserServiceImpl.*(..))")
public void before(){
System.out.println("业务前调用--注解版");
} @After("execution(* com.spring.UserServiceImpl.*(..))")
public void after(){
System.out.println("业务后调用---注解版");
}
}

实例化对象以及配置AOP: 要开启AOP注解支持

<bean id="userService" class="com.spring.UserServiceImpl"></bean>

<bean id="myLog" class="com.spring.log.MyLog"></bean>

<!--开启AOP的注解支持-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

测试:

测试方法基于【Spring API实现AOP】

打印结果:

业务前调用--注解版
添加了一个用户
业务后调用---注解版

Spring5:面向切面的更多相关文章

  1. 面向过程(POP)、面向对象(OOP)、面向接口(IOP)、面向切面(AOP)

    面向过程:典型的是C/C++的结构体,结构体里只有变量,没有处理变量的方法,需要专门编写处理变量的方法. 面向对象:ArrayList<Integer> list=new ArrayLis ...

  2. AOP 面向切面编程, Attribute在项目中的应用

    一.AOP(面向切面编程)简介 在我们平时的开发中,我们一般都是面对对象编程,面向对象的特点是继承.多态和封装,我们的业务逻辑代码主要是写在这一个个的类中,但我们在实现业务的同时,难免也到多个重复的操 ...

  3. javascript面向切面

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. AOP面向切面编程的四种实现

     一.AOP(面向切面编程)的四种实现分别为最原始的经典AOP.代理工厂bean(ProxyFacteryBean)和默认自动代理DefaultAdvisorAutoProxyCreator以及Bea ...

  5. spring入门(四)【面向切面编程】

    开发过程中很多时候会用到日志.事务等操作,这些操作如果要写在业务代码中会相当麻烦,这时就会用到面向切面编程(AOP),AOP作为一种编程思想,和OOP有着不同的侧重点,面向对象侧重于万事万物皆对象,而 ...

  6. 面向切面编程AOP

    本文的主要内容(AOP): 1.AOP面向切面编程的相关概念(思想.原理.相关术语) 2.AOP编程底层实现机制(动态代理机制:JDK代理.Cglib代理) 3.Spring的传统AOP编程的案例(计 ...

  7. Spring-AOP面向切面编程

    AOP是面向切面编程,区别于oop,面向对象,一个是横向的,一个是纵向. 主要解决代码分散和混乱的问题. 1.概念: 切面:实现AOP共有的类 通知:切面类中实现切面功能的方法 连接点:程序被通知的特 ...

  8. AOP 面向切面编程

    AOP http://blog.csdn.net/xiang_j2ee/article/details/6851963 Android 支持 AspectJ 这个库来实现面向切面编程. 使用 Apac ...

  9. 关于面向切面编程Aspect Oriented Programming(AOP)

    最近学到spring ,出来了一个新概念,面向切面编程,下面做个笔记,引自百度百科. Aspect Oriented Programming(AOP),面向切面编程,是一个比较热门的话题.AOP主要实 ...

随机推荐

  1. shell脚本基础知识以及变量

    一.基础知识 1.shell脚本的格式注意事项 第一行(一般必须写明):指定脚本使用的shell(若不写明也不影响脚本的执行,系统会自动以sh解析脚本)."#!/bin/bash" ...

  2. 深度学习、物联网专家Sunil Kumar Vuppala博士独家专访

    介绍 有多种方法可以学习数据科学,机器学习和深度学习概念.您可以观看视频,阅读文章,参加课程,参加会议等.但是有一件事是无法替代的----经验. 我个人从与数据科学专家和行业领袖的交流中学到了很多.他 ...

  3. 使用Python+OpenCV进行图像处理(二)| 视觉入门

    [前言]图像预处理对于整个图像处理任务来讲特别重要.如果我们没有进行恰当的预处理,无论我们有多么好的数据也很难得到理想的结果. 本篇是视觉入门系列教程的第二篇.整个视觉入门系列内容如下: 理解颜色模型 ...

  4. coding++:mybatis update foreach (SQL循环)批量更新

    今天要做批量更新的业务,采用 mybaits 的 foreach 动态语句,遇到一些问题做下记录. 参考示例(1): <update id="" parameterType= ...

  5. Reactor模式和Proactor模式

    Reactor 主线程往epoll内核事件表中注册socket上的读就绪事件 主线程调用epoll_wait等待socket上有数据可读 当socket上有数据可读时,epoll_wait通知主线程, ...

  6. Python学习笔记:函数和变量详解

    一.面向对象:将客观世界的事物抽象成计算机中的数据结构 类:用class定义,这是当前编程的重点范式,以后会单独介绍. 二.函数编程:逻辑结构化和过程化的一种编程方法 1.函数-->用def定义 ...

  7. E 比赛评分

    时间限制 : - MS   空间限制 : - KB  评测说明 : 1s,128m 问题描述 Lj​最近参加一个选秀比赛,有N个评委参加了这次评分,N是奇数.评委编号为1到N.每位评委给Lj​的分数是 ...

  8. [转载]Docker容器无法被stop or kill问题

    来源: 问题过程 某环境一个mysql容器无法被stop or kill or rm sudo docker ps | grep mysql 查看该容器 7844250860f8 mysql:5.7. ...

  9. MySQL入门,第五部分,表结构的修改

    ALTER TABLE <基本表名> [ ADD <新列名> <列数据类型> [列完整性约束] DROP COLUMN <列名> MODIFY < ...

  10. hadoop(九)启动|关闭集群(完全分布式六)|11

    前置章节:hadoop集群namenode启动ssh免密登录(hadoop完全分布式五)|11 集群启动 配置workers(3.x之前是slaves), 删除localhost,添加102/103/ ...