代理模式(Proxy)是通过代理对象访问目标对象,这样可以在目标对象基础上增强额外的功能,如添加权限,访问控制和审计等功能。代理类能增强委托类的行为,代理类和委托类有共同的父类或父类接口,这也就要求代理类和委托类有相似的行为;
二,静态代理;1)第一步
public interface IMarry {
void HappyMarry();
}
2)第二步
public class You implements IMarry{
@Override
public void HappyMarry() {
System.out.println("你结婚了.自己的逻辑");
}
}
3)第三步
public class Wedding implements IMarry{
private IMarry you;
public Wedding(IMarry you) {
this.you = you ;
}
@Override
public void HappyMarry() {
befor();
you.HappyMarry();
after();
}
private void befor() {
System.out.println("结婚前布置现场,结婚前的公共逻辑");
}
private void after() {
System.out.println("结婚后,结算,,结婚后的公共逻辑");
}
}
4)测试 ,在上述步骤之中主要运用到了java多态的特性,因为增强类和目标类实现了同一接口的方法,在通过调用增强类的构造方法,将目标类的方法变成了统一接口的实现,从而利用多态的特性,给目标类实现了增强。
public static void main(String[] args) {
You you = new You();
Wedding wedding = new Wedding(you);
wedding.HappyMarry();
}
三,JDK动态代理
相对于静态代理而言,动态代理则更为灵活。因为静态代理是针对某个行为的定制化开发,如,结婚需要增强那代理类和目标类都需要实现结婚的接口,租房那就需要租房的代理类和接口。时间越久代码臃肿。动态代理由java反射机制实现,会动态的创建代理对象,大大提高程序的可扩展性,达到代码通用的目的;
1)第一步,和静态代理一样实现统一接口
2)第二步,编写代理类,通过实现jdk的InvocationHandler,来实现动态代理
3)第三步 调用动态代理实现动态增强
AOP (Aspect Orient Programming),直译过来就是 面向切面编程。AOP 是一种编程思想,是面向对象编程(OOP)的一种补充。面向对象编程将程序抽象成各个层次的对象,而面向切面编程是将程序抽象成各个切面。主要运用于日志记录,性能监控,安全控制,事务处理,等一些公共功能的重复使用的地方
-
主要特点:
降低模块之间的耦合性,达到高类聚,低耦合;
提高代码的复用性;
提高系统的扩展性,可以在不影响原功能的情况下增加新功能; -
相关概念:
连接点(joinPoint): 增强执行的位置(增加代码的位置)。在 SpringAOP中连接点总是方法的调用。
切入点(PointCut): 可以插入增强处理的连接点,一般可能通过一个表达式来描述。
切面(Aspect): 切面是通知和切点的结合。
通知(Advice): AOP 框架中的增强处理。通知描述了切面何时执行以及如何执行增强处理。
前置增强,后置增强,异常增强,环绕增强
引入(Introduction):特殊的增强,动态为类增加方法。
织入(Weaving): 将增强处理添加到目标对象中,并创建一个被增强的对象,这个过程就是织入。织入分 为三种时期;
编译器:AspectJ
类加载
运行期:jdk动态代理(实现接口),CGlib(子类,不能用final)
1)引入AOP的依赖
2)再yml文件中开启aop spring.aop.auto=true
3)Aop代码实现
package za.activti.oa.aspect;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.StopWatch;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.SourceLocation;
import org.springframework.stereotype.Component;
import java.util.Arrays;
@Slf4j
@Component//需要将切面交友IOC容器管理
@Aspect //声明当前类是个切面类
public class LogCut {
//@Pointcut("execution(* za.activti.oa.service.serviceImpl.*(..))")
//注意这使用注解的方式
@Pointcut("@annotation(za.activti.oa.aspect.SysLog)")
public void cut(){
}
@Before(value = "cut()")
public void before(JoinPoint joinPoint){
Object[] args = joinPoint.getArgs();
Signature signature = joinPoint.getSignature();
Object target = joinPoint.getTarget();
Object aThis = joinPoint.getThis();
JoinPoint.StaticPart staticPart = joinPoint.getStaticPart();
SourceLocation sourceLocation = joinPoint.getSourceLocation();
String longString = joinPoint.toLongString();
String shortString = joinPoint.toShortString();
log.info("【前置通知】" +
"args={},signature={},target={},aThis={},staticPart={}," +
"sourceLocation={},longString={},shortString={}"
, Arrays.asList(args), signature, target, aThis, staticPart, sourceLocation, longString, shortString);
}
@After(value = "cut()")
public void aspectAfter(JoinPoint joinPoint) {
log.info("【后置通知】kind={}", joinPoint.getKind());
}
@AfterReturning(pointcut = "cut()", returning = "result")
public void aspectAfterReturning(JoinPoint joinPoint, Object result) {
log.info("【返回通知】,shortString={},result=", joinPoint.toShortString(), result);
}
@AfterThrowing(pointcut = "cut()", throwing = "ex")
public void aspectAfterThrowing(JoinPoint jp, Exception ex) {
String methodName = jp.getSignature().getName();
if (ex instanceof ArithmeticException) {
log.info("【异常通知】" + methodName + "方法算术异常(ArithmeticException):" + ex.getMessage());
} else {
log.info("【异常通知】" + methodName + "方法异常:" + ex.getMessage());
}
}
@Around(value = "cut()")
public Object handleControllerMethod(ProceedingJoinPoint joinPoint) throws Throwable {
StopWatch stopWatch = StopWatch.createStarted();
log.info("【环绕通知】执行接口开始,方法={},参数={} ", joinPoint.getSignature(), Arrays.asList(joinPoint.getArgs()).toString());
//继续下一个通知或目标方法调用,返回处理结果,如果目标方法发生异常,则 proceed 会抛异常.
//如果在调用目标方法或者下一个切面通知前抛出异常,则不会再继续往后走.
Object proceed = joinPoint.proceed(joinPoint.getArgs());
stopWatch.stop();
long watchTime = stopWatch.getTime();
log.info("【环绕通知】执行接口结束,方法={}, 返回值={},耗时={} (毫秒)", joinPoint.getSignature(), proceed, watchTime);
return proceed;
}
}
3)自定义注解
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@documented
public @interface SysLog {
String value() default "";
}
4)自定义注解使用
@PostMapping("/test")
@SysLog("增加测试日志")
public String test(){
return "ok";
}
5)切入点表达式常用举例
-
execution(* com.wmx.aspect.EmpServiceImpl.findEmpById(Integer)) 匹配 com.wmx.aspect.EmpService 类中的 findEmpById 方法,且带有一个 Integer 类型参数。
-
execution(* com.wmx.aspect.EmpServiceImpl.findEmpById(*)) 匹配 com.wmx.aspect.EmpService 类中的 findEmpById 方法,且带有一个任意类型参数。
-
execution(* com.wmx.aspect.EmpServiceImpl.findEmpById(…)) 匹配 com.wmx.aspect.EmpService 类中的 findEmpById 方法,参数不限。
-
execution(* grp.basic3.se.service.SEBasAgencyService3.editAgencyInfo(…)) || execution(* grp.basic3.se.service.SEBasAgencyService3.adjustAgencyInfo(…)) 匹配 editAgencyInfo 方法或者 adjustAgencyInfo 方法
-
execution(* com.wmx.aspect.EmpService.*(…)) 匹配 com.wmx.aspect.EmpService 类中的任意方法
-
execution(* com.wmx.aspect..(…)) 匹配 com.wmx.aspect 包(不含子包)下任意类中的任意方法
-
execution(* com.wmx.aspect….(…)) 匹配 com.wmx.aspect 包及其子包下任意类中的任意方法
-
execution(public *(…)) 执行所有公共方法
-
execution(* set*(…)) 执行所任意set方法



