CGLIB字节码增强

l没有接口,只有实现类。

采用字节码增强框架 cglib,在运行时 创建目标类的子类,从而对目标类进行增强。

导入jar包:

自己导包(了解):

核心:hibernate-distribution-3.6.10.Final\lib\bytecode\cglib\cglib-2.2.jar

依赖:struts-2.3.15.3\apps\struts2-blank\WEB-INF\lib\asm-3.3.jar

spring-core..jar 已经整合以上两个内容

目标类

UserServiceImpl.java
package com.jd.proxy.cglib;

public class UserServiceImpl {

    public void addUser() {
System.out.println("a_proxy.b_cglib addUser");
} public void updateUser() {
System.out.println("a_proxy.b_cglib updateUser"); } public void deleteUser() { System.out.println("a_proxy.b_cglib deleteUser");
} }

切面类

MyAspect
package com.jd.proxy.cglib;

public class MyAspect {

    public void before(){
System.out.println("鸡首2");
} public void after(){
System.out.println("牛后2");
} }

工厂类

MyBeanFactory.java
package com.jd.proxy.cglib;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy; import java.lang.reflect.Method; /**
* @author weihu
* @date 2018/8/16/016 23:48
*/
public class MyBeanFactory { public static UserServiceImpl createService() {
//1.目标类
UserServiceImpl userService = new UserServiceImpl();
//2.切面类
MyAspect myAspect = new MyAspect();
// 3.代理类 ,采用cglib,底层创建目标类的子类
//3.1 核心类
Enhancer enhancer = new Enhancer();
//3.2 确定父类
enhancer.setSuperclass(userService.getClass());
/* 3.3 设置回调函数 , MethodInterceptor接口 等效 jdk InvocationHandler接口
* intercept() 等效 jdk invoke()
* 参数1、参数2、参数3:以invoke一样
* 参数4:methodProxy 方法的代理
*
*
*/
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//前
myAspect.before(); //执行目标类的方法
Object obj = method.invoke(userService, objects);
// * 执行代理类的父类 ,执行目标类 (目标类和代理类 父子关系)
// methodProxy.invokeSuper(o,objects); //后
myAspect.after();
return obj;
}
});
UserServiceImpl proxService = (UserServiceImpl) enhancer.create();
return proxService;
}
}

测试

TestCglib.java
package com.jd.proxy.cglib;

import org.junit.Test;

/**
* @author weihu
* @date 2018/8/16/016 23:55
*/
public class TestCglib { @Test
public void testCglib(){
UserServiceImpl service = MyBeanFactory.createService();
service.addUser();
service.updateUser();
service.deleteUser();
}
}

AOP联盟通知类型


l AOP联盟为通知Advice定义了org.aopalliance.aop.Advice

l Spring按照通知Advice在目标类方法的连接点位置,可以分为5类

前置通知 org.springframework.aop.MethodBeforeAdvice
在目标方法执行前实施增强
后置通知 org.springframework.aop.AfterReturningAdvice
在目标方法执行后实施增强
环绕通知 org.aopalliance.intercept.MethodInterceptor
在目标方法执行前后实施增强
异常抛出通知 org.springframework.aop.ThrowsAdvice
在方法抛出异常后实施增强
引介通知 org.springframework.aop.IntroductionInterceptor
在目标类中添加一些新的方法和属性
环绕通知,必须手动执行目标方法 try{ //前置通知 //执行目标方法 //后置通知 } catch(){ //抛出异常通知 }

spring编写代理:半自动

让spring 创建代理对象,从spring容器中手动的获取代理对象。

导入jar包:

核心:4+1

AOP:AOP联盟(规范)、spring-aop (实现)

目标类

UserService.java

package com.jd.proxy.factorybean;

public interface UserService {

    public void addUser();
public void updateUser();
public void deleteUser(); }

切面类

MyAspect.java
package com.jd.proxy.factorybean;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation; /**
* 切面类中确定通知,需要实现不同接口,接口就是规范,从而就确定方法名称。
* 采用“环绕通知” MethodInterceptor
*/
public class MyAspect implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
System.out.println("前"); //手动执行目标方法
Object obj = methodInvocation.proceed(); System.out.println("后");
return obj;
}
}
UserServiceImpl.java
package com.jd.proxy.factorybean;

public class UserServiceImpl implements UserService {

    @Override
public void addUser() {
System.out.println("b_factory_bean addUser");
} @Override
public void updateUser() {
System.out.println("b_factory_bean updateUser"); } @Override
public void deleteUser() { System.out.println("b_factory_bean deleteUser");
} }

spring配置

beans.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 创建目标类 -->
<bean id="userServiceId" class="com.jd.proxy.factorybean.UserServiceImpl"></bean>
<!-- 创建切面类 -->
<bean id="myAspectId" class="com.jd.proxy.factorybean.MyAspect"></bean> <!-- 创建代理类
* 使用工厂bean FactoryBean ,底层调用 getObject() 返回特殊bean
* ProxyFactoryBean 用于创建代理工厂bean,生成特殊代理对象
interfaces : 确定接口们
通过<array>可以设置多个值
只有一个值时,value=""
target : 确定目标类
interceptorNames : 通知 切面类的名称,类型String[],如果设置一个值 value=""
optimize :强制使用cglib
<property name="optimize" value="true"></property>
底层机制
如果目标类有接口,采用jdk动态代理
如果没有接口,采用cglib 字节码增强
如果声明 optimize = true ,无论是否有接口,都采用cglib -->
<bean id="proxyServiceId" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interfaces" value="com.jd.proxy.factorybean.UserService"></property>
<property name="target" ref="userServiceId"></property>
<property name="interceptorNames" value="myAspectId"></property>
</bean>
</beans>

测试

TestFactoryBean.java
package com.jd.proxy.factorybean;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; /**
* @author weihu
* @date 2018/8/18/018 18:11
*/
public class TestFactoryBean { @Test
public void testAop(){
String xmlPath="com/jd/proxy/factorybean/beans.xml"; //获得代理类
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
UserService userService = (UserService) applicationContext.getBean("proxyServiceId");
userService.addUser();
userService.updateUser();
userService.deleteUser();
}
}

spring aop编程:全自动【掌握】

从spring容器获得目标类,如果配置aop,spring将自动生成代理。

要确定目标类,aspectj 切入点表达式,导入jar包

spring-framework-3.0.2.RELEASE-dependencies\org.aspectj\com.springsource.org.aspectj.weaver\1.6.8.RELEASE

 spring配置

beans.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 id="userServiceId" class="com.jd.proxy.aop.UserServiceImpl"></bean>
<!-- 创建切面类(通知) -->
<bean id="myAspectId" class="com.jd.proxy.aop.MyAspect"></bean>
<!-- aop编程
3.1 导入命名空间
3.2 使用 <aop:config>进行配置
proxy-target-class="true" 声明时使用cglib代理
<aop:pointcut> 切入点 ,从目标对象获得具体方法
<aop:advisor> 特殊的切面,只有一个通知 和 一个切入点
advice-ref 通知引用
pointcut-ref 切入点引用
3.3 切入点表达式
        
execution(* com.itheima.c_spring_aop.*.*(..))
选择方法 返回值任意 包 类名任意 方法名任意 参数任意 -->
<aop:config proxy-target-class="true">
<aop:pointcut expression="execution(* com.itheima.c_spring_aop.*.*(..))" id="myPointCut"/>
<aop:advisor advice-ref="myAspectId" pointcut-ref="myPointCut"/>
</aop:config>
</beans>
MyAspect.java
package com.jd.proxy.aop;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation; /**
* 切面类中确定通知,需要实现不同接口,接口就是规范,从而就确定方法名称。
* * 采用“环绕通知” MethodInterceptor
*
*/
public class MyAspect implements MethodInterceptor { @Override
public Object invoke(MethodInvocation mi) throws Throwable { System.out.println("前4"); //手动执行目标方法
Object obj = mi.proceed(); System.out.println("后4");
return obj;
}
}
UserService.java
package com.jd.proxy.aop;

public interface UserService {

    public void addUser();
public void updateUser();
public void deleteUser(); }
UserServiceImpl.java
package com.jd.proxy.aop;

public class UserServiceImpl implements UserService {

    @Override
public void addUser() {
System.out.println("c_spring_aop addUser");
} @Override
public void updateUser() {
System.out.println("c_spring_aop updateUser"); } @Override
public void deleteUser() { System.out.println("c_spring_aop deleteUser");
} }
TestSpringAOP.java
package com.jd.proxy.aop;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; /**
* @author weihu
* @date 2018/8/18/018 18:21
*/
public class TestSpringAOP { @Test
public void testAop(){
String xmlPath="com/jd/proxy/aop/beans.xml";
ApplicationContext applicationContext=new ClassPathXmlApplicationContext(xmlPath); //获得目标类
UserService userService = (UserService) applicationContext.getBean("userServiceId");
userService.addUser();
userService.updateUser();
userService.deleteUser();
}
}

8.AOP全自动的更多相关文章

  1. Spring全自动AOP和项目加入jar包

    一.jar可以引进项目中,复制到路下后,要add as library,加载到工作空间中才能引入: 也jar包放在硬盘的项目目录外面,可以多个项目引入共用: 二.xml配置 1.aop全自动配置 2. ...

  2. Spring框架的基本使用(AOP部分)

    AOP,Aspect Oriented Programming,意为面向切面编程,是通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术.AOP采取横向抽取机制,取代了传统纵向继承体系重复 ...

  3. Spring常用配置

    ----------------------------------------------------------------------------------------------[版权申明: ...

  4. AOP 手动,半自动,全自动

    dao层 package com.yaorange.dao; public interface StudentDao { public void saveStudent(); public void ...

  5. spring的aop编程(半自动、全自动)

    1.spring的半自动代理(从spring中获取代理对象) (1)spring中的通知类型 spring中aop的通知类型有五种: 前置:在目标方法执行前实施加强 后置:在目标方法执行后实施加强 环 ...

  6. spring(二) AOP之AspectJ框架的使用

    前面讲解了spring的特性之一,IOC(控制反转),因为有了IOC,所以我们都不需要自己new对象了,想要什么,spring就给什么.而今天要学习spring的第二个重点,AOP.一篇讲解不完,所以 ...

  7. Spring框架-AOP详细学习[转载]

    参考博客:https://blog.csdn.net/qq_22583741/article/details/79589910#4-%E4%BE%9D%E8%B5%96%E6%B3%A8%E5%85% ...

  8. spring学习(二) ———— AOP之AspectJ框架的使用

    前面讲解了spring的特性之一,IOC(控制反转),因为有了IOC,所以我们都不需要自己new对象了,想要什么,spring就给什么.而今天要学习spring的第二个重点,AOP.一篇讲解不完,所以 ...

  9. AOP切面编程

    1.JDK动态代理方式实现 public static UserService createService(){ //目标类 final UserService userService = new U ...

随机推荐

  1. lvm管理:扩展lv、删除pv、lv等

    从卷组VG里扩展lv.删除pv,并删除物理卷PV 一.扩展LV.缩小LV 1.卸载LV 命令:umount  "挂载目录" 2.扩展LV 命令:lvextend -L +500m  ...

  2. js 模拟css3 动画

    <html> <head> <title> javaScript缓动入门 </title> </head> <body> < ...

  3. Connection reset by peer原理解析

    “Connection reset by peer”代表什么?“Connection reset by peer”表示当前服务器接受到了通信对端发送的TCP RST信号,即通信对端已经关闭了连接,通过 ...

  4. [Ting's笔记Day7]活用套件carrierwave gem:(2)利用Amazon S3架设图片服务器

    来到第7篇了!培养写作习惯真是不容易:) 在我的上一篇文章活用套件carrierwave gem:(1)在Rails实现图片上传功能,上传图片功能已经完成啦!但是目前图片仅能上传在自己的本地文件夹内孤 ...

  5. c#mvc实现登录

    本篇介绍MVC实现登录的方式,如下: 1.通过MVC Form 表单请求实现登录 2.通过AJAX GET 请求MVC Controller 实现登录 3.通过AJAX POST 请求MVC Cont ...

  6. oracle 连接字符串的问题

    未指定的错误,发生了一个 Oracle 错误,但无法从 Oracle 中检索错误信息.数据类型不被支持. 原因是你用的ADO   for   ORACLE的驱动是微软的Microsoft OLE DB ...

  7. java学习笔记(六):变量类型

    java一共三种变量: 局部变量(本地变量):方法调用时创建,方法结束时销毁 实例变量(全局变量):类创建时创建,类销毁时销毁 类变量(静态变量):程序启动是创建,程序销毁时销毁 public cla ...

  8. springboot整合mybatis遇到的那些坑

    1.接口类(指*Mapper.java)在spring中注册的问题 当控制台打印如下信息: A component required a bean named '*Mapper' that could ...

  9. zabbix钉钉报警

    我们在钉钉上建立群聊,然后在群聊上添加钉钉机器人: 编写,脚本需要放在zabbix 的alertscripts目录下(如果不知道该目录的位置,可以使用find命令查找) find / -iname a ...

  10. PEiD中识别虚拟地址和物理地址

    可通过PEiD中的信息计算文件偏移地址,从而修改PE文件的关键内容,达到破解目的. 文件偏移地址=相对虚拟地址-节偏移. PEiD中有: 节偏移=虚拟地址VOffset-物理地址ROffset.