一.(code generation library)简介
是一个开源项目,是一个强大的,高性能,高质量的code生成类库,它可以在运行期间扩展java类与实现java接口Hibernate支持它来实现PO(Persistent Object),它的底层 是通过使用一个小而快的字节码框架ASM,来转换成java的字节码。
JDK13就就引进了动态代理,CGLIB通过产生代理类的子类来实现动态代理。
class UserServiceImpl {
public void login(String name, String pwd) {
// TODO Auto-generated method stub
System.out.println("检测用户登录的服务!");
}
}
class CglibProxy implements MethodInterceptor {
private Enhancer enhancer = new Enhancer();
/**
* 为实现类动态产生一个子类对象
* @param clazz
* @return
*/
public <T> T getProxy(Class<T> clazz) {
// 设置需要创建子类的类
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
// 通过字节码技术动态创建子类实例
return (T) enhancer.create();
}
// 实现MethodInterceptor接口方法
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
// TODO Auto-generated method stub
System.out.println("前置代理");
// 通过代理类调用父类中的方法
//method.invoke(obj, args);
Object result = proxy.invokeSuper(obj, args);
System.out.println("后置代理");
return result;
}
}
public class TestCGlib {
@Test
public void test1() {
//通过生成子类的方式创建代理类
UserServiceImpl proxyImp = new CglibProxy().getProxy(UserServiceImpl.class);
System.out.println(proxyImp.getClass());
proxyImp.login("zhang san", "111111");
}
}
二.AOP(面向切面编程)
它是可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态添加功能的一种技术,它是一种新的方法轮,是 对传统OOP的一种补充。
常用术语
通知: 新增的AOP功能类的方法都叫通知
连接点:服务类所有的接口都称作连接点
切点:被增强功能的服务类接口称作切点
切面:包含了一组通知和对应的切点
织入:把切面定义的通知,在选定好的切点上,把功能织入到连接点上
目标对象:被代理的对象 UserServiceImpl
代理对象:Spring AOP通过Proxy或者CGLib产生的动态代理类对象
1基于XML方式的AOP的使用
(1)先配置切面的支持类
<bean id="testLogModel" class="com.web.aop.TestLogModel"></bean>
(2)然后开始配置切点和切面,以及切面拥有的通知,切面引用对应的支持类
<aop:config>
<aop:pointcut expression="execution(* com.service.impl.*.checkUser(..))" id="pointcut01"/>
<aop:aspect ref="testLogModel">
<aop:before method="addBefore" pointcut- ref="pointcut01"/>
</aop:aspect>
<aop:aspect ref="testLogModel">
<aop:after method="addAfter" pointcut-ref="pointcut01"/>
</aop:aspect>
</aop:config>
(3)如何在通知方法上获取连接点的所有信息
public void addBefore(JoinPoint point){
System.out.println(point.getStaticPart());
System.out.println(point.getArgs());
System.out.println("前置的功能增强");
}
2.基于注解方式
“`
(1)引入spring-aop的jar包还要引入一个第三方的aop框架aspectj的jar包
(2)在spring.xml文件中引入aop标签以及功能
(3)创建aop功能的类(比如日志管理,事务管理,安全管理)
(4)在xml文件中或者使用注解方式,把aop功能类添加到服务类的模块当中
@Aspect 包含通知功能的切面支持类
@After 前置通知,在连接方法前执行
@Around 环绕通知,在连接方法前后执行
@AfterReturning 后置返回通知,可以接受连接点方法调用完的返回值
@AfterThrowing 异常通知
注意:环绕通知相当于代替的method.invoke()方法,所以在写环绕通知时要自己写调用invoke方法,如果后续还有后置返回通知,环绕通知还必须返回连接点方法运行后的返回值
@Aspect
public class TestLogModel{
@Pointcut("execution(* com.service.impl.*.check*(..))"+ "&& args=(name,pwd)")
public void pointcut01(String name,String pwd){
}
@Before("pointcut01(name,pwd)")
public void addBefore(String name, String pwd){
System.out.println("aop => " + "name:" + name + " pwd:" + pwd);
System.out.println("前置的功能增强");
}
@After("pointcut01(name,pwd)")
public void addAfter(){
System.out.println("后置的功能增强");
}
/**
* 环绕通知
* @throws Throwable
*/
@Around("pointcut01(name,pwd)")
public void addAround(ProceedingJoinPoint point) throws Throwable{
System.out.println("前置的环绕通知");
System.out.println(point.getTarget());
System.out.println(Arrays.toString(point.getArgs()));
System.out.println(point.toLongString());
//调用委托类的方法,在环绕通知时,invoke方法直接被环绕通知代替,用户必须要自己调用委托类方法,
//在写后置返回通知是,环绕通知不能写成比void类型,因为后置返回通知的ret直接调用的是后置返回通知的返回值
point.proceed();
System.out.println("后置的环绕通知");
}
@AfterReturning(pointcut="pointcut01(name,pwd)" ,returning="tet")
public void addAfterReturnning(boolean ret){
System.out.println("ret:" + ret);
}
/**
* 如何把连接点执行抛出的异常,传到这个后置异常通知的参数里面呢?
* @param e
*/
@AfterThrowing("pointcut01(name,pwd)")
public void addAfterThrowing(Exception e){
System.out.println(e);
}
}