Spring5:面向切面
静态代理
缺点:一个真实角色就会产生一个代理角色,代码量会翻倍!
场景:要在写好的实现方法上加入日志功能(公共功能),不要修改原代码
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:面向切面的更多相关文章
- 面向过程(POP)、面向对象(OOP)、面向接口(IOP)、面向切面(AOP)
面向过程:典型的是C/C++的结构体,结构体里只有变量,没有处理变量的方法,需要专门编写处理变量的方法. 面向对象:ArrayList<Integer> list=new ArrayLis ...
- AOP 面向切面编程, Attribute在项目中的应用
一.AOP(面向切面编程)简介 在我们平时的开发中,我们一般都是面对对象编程,面向对象的特点是继承.多态和封装,我们的业务逻辑代码主要是写在这一个个的类中,但我们在实现业务的同时,难免也到多个重复的操 ...
- javascript面向切面
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- AOP面向切面编程的四种实现
一.AOP(面向切面编程)的四种实现分别为最原始的经典AOP.代理工厂bean(ProxyFacteryBean)和默认自动代理DefaultAdvisorAutoProxyCreator以及Bea ...
- spring入门(四)【面向切面编程】
开发过程中很多时候会用到日志.事务等操作,这些操作如果要写在业务代码中会相当麻烦,这时就会用到面向切面编程(AOP),AOP作为一种编程思想,和OOP有着不同的侧重点,面向对象侧重于万事万物皆对象,而 ...
- 面向切面编程AOP
本文的主要内容(AOP): 1.AOP面向切面编程的相关概念(思想.原理.相关术语) 2.AOP编程底层实现机制(动态代理机制:JDK代理.Cglib代理) 3.Spring的传统AOP编程的案例(计 ...
- Spring-AOP面向切面编程
AOP是面向切面编程,区别于oop,面向对象,一个是横向的,一个是纵向. 主要解决代码分散和混乱的问题. 1.概念: 切面:实现AOP共有的类 通知:切面类中实现切面功能的方法 连接点:程序被通知的特 ...
- AOP 面向切面编程
AOP http://blog.csdn.net/xiang_j2ee/article/details/6851963 Android 支持 AspectJ 这个库来实现面向切面编程. 使用 Apac ...
- 关于面向切面编程Aspect Oriented Programming(AOP)
最近学到spring ,出来了一个新概念,面向切面编程,下面做个笔记,引自百度百科. Aspect Oriented Programming(AOP),面向切面编程,是一个比较热门的话题.AOP主要实 ...
随机推荐
- shell脚本基础知识以及变量
一.基础知识 1.shell脚本的格式注意事项 第一行(一般必须写明):指定脚本使用的shell(若不写明也不影响脚本的执行,系统会自动以sh解析脚本)."#!/bin/bash" ...
- 深度学习、物联网专家Sunil Kumar Vuppala博士独家专访
介绍 有多种方法可以学习数据科学,机器学习和深度学习概念.您可以观看视频,阅读文章,参加课程,参加会议等.但是有一件事是无法替代的----经验. 我个人从与数据科学专家和行业领袖的交流中学到了很多.他 ...
- 使用Python+OpenCV进行图像处理(二)| 视觉入门
[前言]图像预处理对于整个图像处理任务来讲特别重要.如果我们没有进行恰当的预处理,无论我们有多么好的数据也很难得到理想的结果. 本篇是视觉入门系列教程的第二篇.整个视觉入门系列内容如下: 理解颜色模型 ...
- coding++:mybatis update foreach (SQL循环)批量更新
今天要做批量更新的业务,采用 mybaits 的 foreach 动态语句,遇到一些问题做下记录. 参考示例(1): <update id="" parameterType= ...
- Reactor模式和Proactor模式
Reactor 主线程往epoll内核事件表中注册socket上的读就绪事件 主线程调用epoll_wait等待socket上有数据可读 当socket上有数据可读时,epoll_wait通知主线程, ...
- Python学习笔记:函数和变量详解
一.面向对象:将客观世界的事物抽象成计算机中的数据结构 类:用class定义,这是当前编程的重点范式,以后会单独介绍. 二.函数编程:逻辑结构化和过程化的一种编程方法 1.函数-->用def定义 ...
- E 比赛评分
时间限制 : - MS 空间限制 : - KB 评测说明 : 1s,128m 问题描述 Lj最近参加一个选秀比赛,有N个评委参加了这次评分,N是奇数.评委编号为1到N.每位评委给Lj的分数是 ...
- [转载]Docker容器无法被stop or kill问题
来源: 问题过程 某环境一个mysql容器无法被stop or kill or rm sudo docker ps | grep mysql 查看该容器 7844250860f8 mysql:5.7. ...
- MySQL入门,第五部分,表结构的修改
ALTER TABLE <基本表名> [ ADD <新列名> <列数据类型> [列完整性约束] DROP COLUMN <列名> MODIFY < ...
- hadoop(九)启动|关闭集群(完全分布式六)|11
前置章节:hadoop集群namenode启动ssh免密登录(hadoop完全分布式五)|11 集群启动 配置workers(3.x之前是slaves), 删除localhost,添加102/103/ ...