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();
}
}

最新文章

  1. session失效
  2. SIP 解析
  3. php网页切图/js切图
  4. 020ARM家族
  5. Leetcode#127 Word Ladder
  6. Sqlyog增加试用期
  7. leetcode&mdash;triangle
  8. Qt入门(2)——使用Qt编写的Hello world
  9. 1082. Read Number in Chinese (25)
  10. Android support library支持包常用控件介绍(二)
  11. CentOS7 上安装 MySQL 5.7
  12. android ndk native错误分析方法
  13. Java虚拟机性能管理神器 - VisualVM(4) - JDK版本与VisualVM版本对应关系
  14. Linux下开发python django程序(Cookie读写)
  15. yii2.0 如何按需加载并管理CSS样式及JS脚本
  16. jquery里正则的使用方法及常用的正则验证
  17. mysql数据导入mongoDB
  18. 前端技术俗语js
  19. main方法为什么是静态的
  20. Deferred Shading延迟渲染

热门文章

  1. C++学习基础十七-- 函数指针
  2. python大法好——装饰器、生成器、迭代器
  3. django admin 设置(转载https://www.cnblogs.com/wumingxiaoyao/p/6928297.html)
  4. [java]给出一个字符串,将重复的字符去除,仅保留第一次出现的字符,且保持去重后的字符在原字符串中的顺序不变
  5. Dom文本应用-表格隔行间亮样式
  6. php json 写入 mysql 的例子
  7. KO ----- 静态资源404问题
  8. cookie、sesstion、strorage
  9. 使用手势对UIImageView进行缩放、旋转和移动
  10. linux就该这么学,第十一天了