代理模式
代理,好比一个经纪人,为一个歌手服务,歌手专心唱歌,经纪人为歌手找活干,这里的歌手就是目标对象,经纪人就是代理。
再简单点来说,代理就是包装了某个对象,在对象身上套了层壳子。它可以在使用对象的基础上,增强对象,也就是为这个对象赋予其他能力。比如用代理实现日志功能,在执行某个业务方法后,希望打印执行完毕的日志,那么用代理把业务方法包装,代理调用业务方法并且执行,执行完毕再让代理打印日志。
为什么要用代理?
可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能.
代理类别
- 静态代理
- jdk动态代理
- cglib动态代理
静态代理
缺点
因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类,类太多.同时,一旦接口增加方法,目标对象与代理对象都要维护.
jdk动态代理
特点
代理对象不需要实现接口,但是目标对象一定要实现接口,否则不能用动态代理
cglib动态代理
特点
上面的静态代理和动态代理模式都是要求目标对象是实现一个接口的目标对象,但是有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候就可以使用以目标对象子类的方式类实现代理,这种方法就叫做:Cglib代理
AspectJ框架
Aspectj是一个使用面向切面,底层采用动态代理的框架。
面向切面的好处
AOP主要实现的目的是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果。
说白了,就是分离我们的业务逻辑和系统级逻辑(比如日志,事务处理等),从而降低了类与类之间的耦合,低耦合高内聚永远是我们的追求。
具体的使用方法我就不介绍了,网上都有,仅归纳要点。
- AspectJ 5 种类型的通知注解
- @Before: 前置通知:在方法执行之前执行的通知
- @After: 后置通知, 在方法执行之后执行 , 即方法返回结果或者抛出异常的时候, 下面的后置通知记录了方法的终止.
- @AfterRunning: 返回通知, 在方法返回结果之后执行 无论方法是正常返回还是抛出异常, 后置通知都会执行. 如果只想在方法返回的时候记录日志, 应使用返回通知代替后置通知.
- @AfterThrowing: 异常通知, 在方法抛出异常之后
- @Around: 环绕通知, 围绕着方法执行(即方法前后都有执行) 环绕通知能够全面地控制连接点. 甚至可以控制是否执行连接点.
实际项目中的使用
@Aspect
@Component
public class AspectJ {
@Resource
TotoroUsersPermissionLogMapper totoroUsersPermissionLogMapper;
@Pointcut("execution(* com.fosun.totoro.cicd.service.impl.UsersServiceImpl.addPermission(..))")
private void addPermission(){}
@Pointcut("execution(* com.fosun.totoro.cicd.service.impl.PermissionServiceImpl.deleteByUsernameApplication(..))")
private void deletePermission(){}
@AfterReturning("addPermission()")
public void afterReturingAddPermission(JoinPoint joinPoint){
Object[] args = joinPoint.getArgs();
String username = (String)args[0];
String application = (String)args[1];
LoginUserDetailsImpl users = (LoginUserDetailsImpl) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
TotoroUsersPermissionLog totoroUsersPermissionLog = new TotoroUsersPermissionLog();
totoroUsersPermissionLog.setUsername(users.getUsername());
totoroUsersPermissionLog.setContent("给用户\""+username+"\""+"增加权限\""+application+"\"");
totoroUsersPermissionLogMapper.insertSelective(totoroUsersPermissionLog);
}