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主要实 ...
随机推荐
- Python NLP库top6的介绍和比较
文章来源:ActiveWizards https://medium.com/activewizards-machine-learning-company/comparison-of-top-6-pyt ...
- CVPR 2019细粒度图像分类竞赛中国团队DeepBlueAI获冠军 | 技术干货分享
[导读]CVPR 2019细粒度图像分类workshop的挑战赛公布了最终结果:中国团队DeepBlueAI获得冠军.本文带来冠军团队解决方案的技术分享. 近日,在Kaggle上举办的CVPR 201 ...
- 浅谈服务架构“五脏六腑”之Spring Cloud
本文将从 Spring Cloud 出发,分两小节讲述微服务框架的「五脏六腑」: 第一小节「服务架构」旨在说明的包括两点,一服务架构是什么及其必要性:二是服务架构的基本组成.为什么第一节写服务架构而不 ...
- 6.Maven构建过程的各个环节
构建过程中的各个环节 [1]清理:将以前编译得到的旧的class字节码文件删除,为下一次编译做准备 [2]编译:将Java源程序编译成class字节码文件 [3]测试:自动测试,自动调用junit程序 ...
- -bash: syntax error near unexpected token `newline'问题解决
原因:bash语法错误,例如, 仔细查看发现语句中不能有'<'和'>',删除这两个符号即可: 问题解决!
- CSS样式的4种写法 | 以及选择器的几种用法
CSS样式: 1.内部样式表 <style type="text/css"> 样式表写法 </style> 2.使用link标签,在文档中声明使用 ...
- 解决ASP.NET MVC返回的JsonResult 中 日期类型数据格式问题,和返回的属性名称转为“驼峰命名法”和循环引用问题
DateTime类型数据格式问题 问题 在使用ASP.NET MVC 在写项目的时候发现,返回给前端的JSON数据,日期类型是 Date(121454578784541) 的格式,需要前端来转换一下才 ...
- 【python系统学习13】类(class)与对象(object)
目录: 类(class)和实例 类 实例 小测试 对象(object) 属性和方法 类的创建 伪代码 示例代码 属性(attribute) 方法(method) 类的实例化 实例对象调用类属性和方法 ...
- VAuditDemo-任意文件读取
任意文件读取是属于文件操作漏洞的一种. 一般任意文件读取漏洞可以读取配置信息.甚至系统重要文件. 严重的话,就可能导致SSRF,进而漫游内网. 文件操作漏洞 任意文件删除--删除lock 任意文件复制 ...
- 微信小程序动态修改页面标题setNavigationBarTitle
微信小程序是可以动态修改页面标题的. 首先我们来看看静态是怎么实现的 在对应页面的json文件里面加入下面代码就可以实现了 { "navigationBarTitleText": ...