🌐Hello World !
Sping AOP
Spring AOP:
控制反转
AOP面向切面编程,通过
预编译
方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP
的延续,是软件开发中的一个热点,也是Spring
框架中的一个重要内容,是函数式编程
的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低
,提高程序的可重用性,同时提高了开发的效率
代理模式
代理模式
是程序设计中的一种设计模式
- 所谓的代理者是指一个类别可以作为其它东西的接口。代理者可以作任何东西的接口:网上连接、存储器中的大对象、文件或其它昂贵或无法复制的资源
代理模式分类:
- 静态代理
- 动态代理
优势:
- 真实角色更加纯粹,不用关注公共业务
- 公共业务交给代理角色,实现业务分工
- 公共业务发生扩展时,方便集中管理
劣势:
- 一个真实角色会产生一个代理,代码量会翻倍、效率降低
静态代理
角色分析:
- 抽象角色:一般会使用接口或者抽象类来解决
- 真实代理:被代理的角色
- 代理角色:代理真实角色
- 客户:访问代理对象者
- 接口
public interface Rent { public void rent(); }
- 真实角色
public class Host { public void rent(){ System.out.println("房东房子出租"); } }
- 代理角色
public class Proxy implements Rent{ private Host host; public Proxy() { } public Proxy(Host host) { this.host = host; } public void rent(){ host.rent(); } //看房 public void seeHouse(){ System.out.println("中介带你看房"); } //收中介费 public void money(){ System.out.println("收中介费"); } }
- 客户端访问代理角色
public class Client { public static void main(String[] args) { //创建房东对象 Host host = new Host(); //代理 Proxy proxy = new Proxy(host); //通过代理调用房东对象 proxy.rent(); } }
动态代理
动态代理:
- 动态代理和静态代理角色一样
- 动态代理的代理类是动态生成
- 动态代理是一个接口,对应一类业务
- 动态代理可以代理多个类,只要实现一个接口
动态代理分类:
- 基于接口——JDK动态代理
- 基于类——cglib
- Java字节码——Javasist
两种类了解:
- Proxy——代理
- InvocationHandl——调用处理程序
Proxy类:生成动态代理实例
Proxy
创建动态代理类的实例提供了静态方法,也是所有动态代理类的父类的方法创建方法:
//返回指定的代理实例的调用处理程序 getInvocationHandler(Object proxy) //返回 java.lang.Class对象的代理类,给出了类装载器和一个阵列的接口 getProxyClass(ClassLoader loader, 类<?>... interfaces) //如果指定的类是动态生成的可利用 getProxyClass法或代理类 newProxyInstance方法返回true isProxyClass(类<?> cl) //返回指定的接口,将方法调用指定的调用处理程序的代理类的一个实例。 newProxyInstance(ClassLoader loader, 类<?>[] interfaces, InvocationHandler h)
InvocationHandl类:调用处理程序并返回结果
InvocationHandler
是通过一个代理实例调用处理程序实现的接口。- 每个代理实例都有一个相关的调用处理程序。当一个方法是在一个代理实例调用,调用的方法进行编码并派遣其调用处理程序的
invoke
方法方法:
//在代理实例上处理方法调用,并返回结果 invoke(Object proxy, 方法 method, Object[] args)
- proxy — 调用该方法的代理实例
- method — 反射获取到的接口的方法
- args — 使用此方法时传入的参数数组
- ProxyInvocationHandler动态代理类
public class ProxyInvocationHandl implements InvocationHandler { //被代理的接口 private Object target; public void setTarget(Object target) { this.target = target; } //生成得到代理类 public Object getProxy() { //this.getClass().getClassLoader() 加载类所在位置 //rent.getClass().getInterfaces() 表示代理接口 //this == InvocationHandler实现类 return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } //处理代理实例,并返回结果 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //动态代理的本质,就是使用反射机制 log(method.getName()); Object result = method.invoke(target, args); return result; } public void log(String msg) { System.out.println("执行了" + msg + "方法"); } }
- Client客户类
public class Client { public static void main(String[] args) { //真实角色:被代理的角色 UserServiceImp userService = new UserServiceImp(); //代理角色:代理真实角色 ProxyInvocationHandl pih = new ProxyInvocationHandl(); //设置代理对象 pih.setTarget(userService); //动态生成代理类 UserService proxy = (UserService) pih.getProxy(); proxy.query(); } } /* 执行了query方法 [Debug]使用了query方法 查询用户 */
AOP概述
提供声明式事物,允许用户自定义切面
- 横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是很切关注点,如:日志,安全,缓存,事物……
- 切面(ASPECT):横切关注点被模块化的特殊对象。
- 通知(Advice):切面必须要完成的工作。
- 目标(Target):被通知对象。
- 代理(Proxy):向目标对象应用通知之后创建的对象。
- 切入点(PointCut):切面通知执行的"地点"的定义。
- 连接点(JoinPoint):与切入点匹配的执行点。
Spring实现AOP
方式一:使用Spring的API接口实现AOP
- 使用AOP织入,需要导入一个依赖包
<dependencies> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.4</version> </dependency> </dependencies>
- applicationContext.xml
<?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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd "> </beans>
- 前置Log日志类
public class log implements MethodBeforeAdvice { //method:要执行的目标对象方法 //object:参数 //target:目标对象 @Override public void before(Method method, Object[] objects, Object target) throws Throwable { System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行了"); } }
- 后置AfterLog类
public class AfterLog implements AfterReturningAdvice { //returnValue:返回值 @Override public void afterReturning(Object returnValue, Method method, Object[] objects, Object o1) throws Throwable { System.out.println("执行了"+method.getName()+"放回结果为:"+returnValue); } }
- UserService接口
public interface UserService { public void add(); public void delete(); public void update(); public void select(); }
- UserServiceImpl接口实现类
public class UserServiceImpl implements UserService{ public void add() { System.out.println("增加了一个用户"); } public void delete() { System.out.println("删除了一个用户"); } public void update() { System.out.println("更新了一个用户"); } public void select() { System.out.println("查询了一个用户"); } }
- 将UserServiceImpl接口实现类注册到Spring中,即applicationContext.xml中
<?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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd "> <!--注册bean--> <bean id="userService" class="com.wei.service.UserServiceImpl"/> <bean id="log" class="com.wei.log.log"/> <bean id="agter" class="com.wei.log.AfterLog"/> <!--方式一:使用原生的Spring API接口--> <!--配置aop,需要导入aop的约束--> <aop:config> <!--切入点: execution:表达式 execution(要执行的位置 * * * * *) --> <aop:pointcut id="pointcut" expression="execution(* com.wei.service.UserServiceImpl.*(..))"/> <!--执行环绕增强--> <aop:advisor advice-ref="log" pointcut-ref="pointcut"/> <aop:advisor advice-ref="agter" pointcut-ref="pointcut"/> </aop:config> </beans>
- MyTest测试类
public class MyTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //动态代理的是接口 UserService userService = (UserService) context.getBean("userService"); userService.delete(); } } /* 执行结果: com.wei.service.UserServiceImpl的delete被执行了 删除了一个用户 执行了delete放回结果为:null */
方式二:自定义实现AOP
- 自定义Diy类
public class DiyPointCut { public void before(){ System.out.println("===========方法执行前==========="); } public void after(){ System.out.println("===========方法执行后==========="); } }
- 将Diy类注册到Spring中,即applicationContext.xml中
<!--方式二:自定义类--> <bean id="diy" class="com.wei.diy.DiyPointCut"/> <aop:config> <!--自定义切面:ref要引用的类--> <aop:aspect ref="diy"> <!--切入点--> <!--execution(修饰符返回值 类路径.*(..))--> <aop:pointcut id="point" expression="execution(* com.wei.service.UserServiceImpl.*(..))"/> <!--通知--> <!-- method="before" 自定义的方法名 pointcut-ref="point" 方法执行在point切入点之后 --> <aop:before method="before" pointcut-ref="point"/> <aop:after method="after" pointcut-ref="point"/> </aop:aspect> </aop:config>
- MyTest测试类
public class MyTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //动态代理的是接口 UserService userService = (UserService) context.getBean("userService"); userService.delete(); } } /* ===========方法执行前=========== 删除了一个用户 ===========方法执行后=========== */
aop中execution 表达式(*execution(\* 包名.\*.*(..))*)
整个表达式可以分为五个部分:
- execution(): 表达式主体
- 第一个*号:方法返回类型, *号表示所有的类型
- 包名:表示需要拦截的包名
- 第二个*号:表示类名,*号表示所有的类
- *(…):最后这个星号表示方法名,*号表示所有的方法,后面( )里面表示方法的参数,两个句点表示任何参数
<!--切入点--> <!--execution(修饰符返回值 类路径.*(..))--> <aop:pointcut id="point" expression="execution(* com.wei.service.UserServiceImpl.*(..))"/>
方式三:使用注解实现AOP
- 创建AnnotationPointCut类
//方式三:使用注解实现AOP // @Aspect 标注这个类是一个切面 @Aspect public class AnnotationPointCut { //后置增强 @Before("execution(* com.wei.service.UserServiceImpl.*(..))") public void before() { System.out.println("======方法执行前======"); } //前置增强 @After("execution(* com.wei.service.UserServiceImpl.*(..))") public void after() { System.out.println("======方法执行后======"); } //在环绕增强中,可以给一个参数,代表要获取处理切入的点 @Around("execution(* com.wei.service.UserServiceImpl.*(..))") public void around(ProceedingJoinPoint jp) throws Throwable { System.out.println("======环绕前======"); //执行方法 Object proceed = jp.proceed(); System.out.println("======环绕后======"); } }
- 将AnnotationPointCut类注册到Spring中,即applicationContext.xml中
<!--方式三--> <bean id="AnnotationPointCut" class="com.wei.diy.AnnotationPointCut"/> <!--开启注解支持--> <!-- JDK(默认 proxy-target-class="false") cglib(proxy-target-class="true") --> <aop:aspectj-autoproxy proxy-target-class="true"/>
- MyTest测试类
public class MyTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //动态代理的是接口 UserService userService = (UserService) context.getBean("userService"); userService.delete(); } } /* 执行结果: ======环绕前====== ======方法执行前====== 删除了一个用户 ======环绕后====== ======方法执行后====== */
🌼 结语:创作不易,如果觉得博主的文章赏心悦目,还请——
点赞
👍收藏
⭐️评论
📝冲冲冲
🤞
转载:https://blog.csdn.net/weixin_62765017/article/details/127612410
查看评论