Spring框架——AOP
本文内容纲要:
- 代理模式- 静态代理
- 实现
- 被代理对象
- 代理对象
- 使用
- 缺点:
- 动态代理
- 实现
- AOP (Aspect-Oriented Programmin) 面向切面编程
- 概念
- 通知类型
- AOP实现方式
- SpringAPI传统方式
- 前置通知 MethodBeforeAdvice接口
- 后置通知 AfterReturningAdvice接口
- 环绕通知 MethodInterceptor接口
- 异常通知 ThrowsAdvice接口
- xml配置代理模式
- 使用
- 纯POJO类-基于xml
- 通知类java
- xml配置
- 执行顺序
- 纯POJO类-基于注解驱动
- xml配置
- 注解配置
- 通知顺序
- 后置通知和最终通知的区别
- 使用AspectJ切面
- 每日英语
代理模式
代理模式创建代理对象,让代理对象控制目标对象的访问,并且可以在不改变目标对象的情况下添加一些额外的功能
不破坏原来代码的业务逻辑结构
静态代理
代理对象与被代理对象必须实现同一接口,在代理对象中实现日志
实现
被代理对象
public class UserServiceImpl implements UserService {
public boolean login(String name, String password){
if(name.equals("adi") && password.equals("123")){
System.out.println("业务逻辑:用户adi登录成功");
return true;
}else{
System.out.println("业务逻辑:用户adi登录失败");
return false;
}
}
}
代理对象
package staticproxy;
import java.util.Date;
public class UserServiceStaticProxy implements UserService {
private UserService userService;
public UserServiceStaticProxy(UserService userService) {
this.userService = userService;
}
@Override
public boolean login(String name, String password) {
boolean isLogin = userService.login(name, password);
System.out.println("日志:" + name + "于" + new Date().toLocaleString() + "登录");
return isLogin;
}
}
使用
UserServiceStaticProxy proxy = new UserServiceStaticProxy(new UserServiceImpl());
proxy.login("xxx","xxx");
缺点:
- 代理对象的一个接口只服务于一种类型的对象
- 如果要代理的方法很多,要为每种方法进行代理
- 静态代理在程序规模稍大时无法胜任
动态代理
InvocationHandler
接口,- 操作代理对象时会执行
invoke()
方法, - 使用
Proxy.newProxyInstance()
静态方法建立一个代理类对象(必须告知要代理的接口
实现
public class LoggerHandler implements InvocationHandler { private Object delegate;
public Object bind(Object delegate) {
this.delegate = delegate;
return Proxy.newProxyInstance(delegate.getClass().getClassLoader(), delegate.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
System.out.println("方法名是:"+method.getName());
result = method.invoke(delegate, args);
System.out.println("日志:" + args[0] + "于" + new Date().toLocaleString() + "登录");
return result;
}
}
LoggerHandler lh = new LoggerHandler();
UserService us = (UserService) lh.bind(new UserServiceImpl());
us.login("adi", "123");
AOP (Aspect-Oriented Programmin) 面向切面编程
独立于Spring框架,但Spring实现了AOP。
- 提供一种新的组织程序结构的思路
- 对OOP补充,可OOP一起使用
- OOP核心单位为类、AOP核心单位为切面
概念
- 关注点:特定的问题、概念、或成需要达到的目标。
- 横切关注点:一个关注点被多个类或者方法引用
- 切面:一个切面是对一个横切关注点的模块化,(实现关注点的方法)
- 连接点:程序执行过程中的某个点,方法调用或者抛出异常
- 通知:在特定连接点应执行动作(定义何时)
- 切入点:什么地方植入通知(何地)
- 目标对象:被切面所通知的对象(被代理的对象)
- 织入:将切面应用到目标对象,从而创建新的代理对象
通知类型
- 前置通知(Before advice): 在某连接点之前执行的通知
- 后置通知(After returning advice): 在某连接点正常完成后执行的通知
- 异常通知(After throwing advice): 在方法抛出异常退出时执行的通知
- 最终通知(After finally advice): 当某连接点退出的时候执行的通知
- 环绕通知(Around advice): 包围一个连接点的通知,这是最强大的一种通知类型
AOP实现方式
SpringAPI传统方式
前置通知 MethodBeforeAdvice
接口
public class Md5Advice implements MethodBeforeAdvice { @Override
public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
System.out.println(arg0.getName());
System.out.println(arg1[1]);
System.out.println(arg2.getClass().getName());
String newPwd = Md5Encode.getMD5(arg1[1].toString().getBytes());
arg1[1] = newPwd;
}
}
后置通知 AfterReturningAdvice
接口
public class LogAdvice implements AfterReturningAdvice { @Override
public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable {
System.out.println(arg0);
System.out.println(arg3);
System.out.println(arg2[0]+"在"+new Date().toLocaleString()+"登录");
arg0=false;
}
}
环绕通知 MethodInterceptor
接口
也可决定方法是否执行。
public class TimeAdvice implements MethodInterceptor { @Override
public Object invoke(MethodInvocation arg0) throws Throwable {
System.out.println("方法开始执行时间:"+new Date().toLocaleString());
Object result = arg0.proceed();
System.out.println("方法结束执行时间:"+new Date().toLocaleString());
return result;
}
}
异常通知 ThrowsAdvice
接口
public class RegistExceptionAdvice implements ThrowsAdvice { public void afterThrowing(Exception e) {
System.out.println("异常通知发生异常"+e.getMessage());
}
}
xml配置代理模式
<!--注入代理的接口--><!--注入通知,list配置-->
<!--注入代理目标-->
<bean>
<bean id="UserProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces" value="com.user.UserService"></property>
<property name="interceptorNames">
<list>
<value>Md5Advice</value>
<value>TimeAdvice</value>
</list>
</property>
<property name="target" ref="UserServiceImpl"></property>
</bean>
</beans>
使用
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");//接口获取代理对象
UserService us = (UserService)ctx.getBean("UserProxy");
us.regist("adi", "123");
boolean bool = us.login("adi", "123");
System.out.println(bool);
纯POJO类-基于xml
通知类java
方法名自己写
public class MyAdvice {
public void before(JoinPoint joinPoint) {
System.out.println("前置通知");
}
//参数和配置名一致
public void afterReturning(JoinPoint joinPoint, Object result) {
System.out.println("后置通知");
}
public void after(JoinPoint joinPoint) {
System.out.println("最终通知");
}
public Object around(ProceedingJoinPoint joinPoint) {
System.out.println("环绕通知");
Object[] args = joinPoint.getArgs();
Object result = null;
try {
result = joinPoint.proceed(args);
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("环绕通知");
return result;
}
public void throwMethod(Exception ex) {
System.out.println("异常通知");
}
}
xml配置
- 导入aop的命名空间
- 配置bean元数据
- 配置
<aop:config>
aop:config
<aop:aspect id="MyAspect" ref="MyAdvice" order="2">
<aop:before method="before" pointcut="execution(* com.user.*.*(..))" />
<aop:after-returning method="afterReturning" pointcut="execution(* com.user.*.*(..))" returning="result"/>
<aop:around method="around" pointcut="execution(* com.user.*.*(..))" />
<!--aop:after-throwing method="throwExMethod" pointcut="execution(* service.*.*(..))" throwing="ex"/-->
<aop:after method="after" pointcut="execution(* com.user.*.*(..))" />
</aop:aspect>
</aop:config>
执行顺序
前置通知
环绕通知
业务执行....
最终通知
环绕通知
后置通知
纯POJO类-基于注解驱动
xml配置
- aop自动代理
- 注解配置
<aop:aspectj-autoproxy />
属性proxy-target-class
- false ,jdk动态代理织入增强-代理模式
- true,cglib动态代理织入增强-代理模式(不用加接口)
<aop:aspectj-autoproxy />
<context:annotation-config />
<context:component-scan base-package="com" />
注解配置
组件注解
切面注解
前置通知注解
后置通知注解
环绕通知注解
最终通知注解
异常通知注解
@Order(int)
同类型通知排序(针对类),在类上加@Component
@Aspect
public class MyAdvice {
// @Before("execution(* com.user..(..))")
public void before(JoinPoint joinPoint) {
System.out.println("前置通知");
}
// @AfterReturning(pointcut = "execution(* com.user.UserServiceImpl.*(..))", returning="result")
public void afterReturning(JoinPoint joinPoint, Object result) {
System.out.println("后置通知");
}
// @After("execution(* com.user..(..))")
public void after(JoinPoint joinPoint) {
System.out.println("最终通知");
}
@Around("execution(* com.user.*.*(..))")
public Object around(ProceedingJoinPoint joinPoint) {
System.out.println("环绕通知");
Object[] args = joinPoint.getArgs();
Object result = null;
try {
result = joinPoint.proceed(args);
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("环绕通知");
return result;
}
// @AfterThrowing(value = "execution(* com.user..(..))", throwing="ex")
public void throwMethod(Exception ex) {
System.out.println("异常通知");
}
}
通知顺序
环绕通知
前置通知
业务执行,登录成功
环绕通知
最终通知
后置通知
后置通知和最终通知的区别
后置通知如果出现异常,无法返回数据时,后置通知无法执行,但是最终通知可以执行。
不管有没有异常,最终通知一定执行,
没有异常,返回值正常时,后置通知才执行。
使用AspectJ切面
- 自己找素材看
每日英语
proxy 代理
Invocation 求助,调用
Handler 组织者、操作者
pointcut 切点
本文内容总结:代理模式,静态代理,实现,被代理对象,代理对象,使用,缺点:,动态代理,实现,AOP (Aspect-Oriented Programmin) 面向切面编程,概念,通知类型,AOP实现方式,SpringAPI传统方式,前置通知 MethodBeforeAdvice接口,后置通知 AfterReturningAdvice接口,环绕通知 MethodInterceptor接口,异常通知 ThrowsAdvice接口,xml配置代理模式,使用,纯POJO类-基于xml,通知类java,xml配置,执行顺序,纯POJO类-基于注解驱动,xml配置,注解配置,通知顺序,后置通知和最终通知的区别,使用AspectJ切面,每日英语,
原文链接:https://www.cnblogs.com/occlive/p/13558853.html
以上是 Spring框架——AOP 的全部内容, 来源链接: utcz.com/z/296674.html