重温Spring之旅5——AOP代理对象、JDK动态代理、使用cglib生产代理

AOP——代理对象

代理模式:代理模式的英文叫做Proxy或Surrogate,中文都可译为”代理“,所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动。在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用.

抽象主题角色:声明了真实主题和代理主题的共同接口,这样一来在任何可以使用真实主题的地方都可以是使用代理主题.

代理主题(Proxy)角色:代理主题角色内部含有对真实主题的引用,从而可以在任何时候操作真实主题对象;代理主题角色提供一个与真实主题角色相同的接口,以便可以在任何时候都可以替代真实主题控制对真实主题的引用,负责在需要的时候创建真实主题对象(和删除真实主题对象);代理角色通常在将客户端调用传递给真实的主题之前或之后,都要执行某个操作,而不是单纯地将调用传递给真实主题对象.

真实主题角色:定义了代理角色所代表地真实对象.

代理模式示意图

Subject.java

package com.xbmu.a.aop;

public interface Subject {
	String request();
}

RealSubject.java

package com.xbmu.a.aop;
/**
 * 真实主题
 * @author bitaotao
 *
 */
public class RealSubject implements Subject{

	@Override
	public String request() {
		return "请收取1000元整";
	}

}

ProxySubject.java

package com.xbmu.a.aop;

/**
 * 代理主题
 * @author bitaotao
 *
 */
public class ProxySubject implements Subject{

	private Subject subject;
	private String str;

	@Override
	public String request() {
		if(subject == null){
			subject  = new RealSubject();
		}
		str = subject.request();
		//添加的业务逻辑
		str = str.replaceAll("1000", "2000");
		return str;
	}

}

App.java

package com.xbmu.a.aop;

public class App {
	public static void main(String[] args) {
		Subject subject = new RealSubject();
		System.out.println("真实主题:"+subject.request());
		System.out.println("===================");
		Subject proxySubject = new ProxySubject();
		System.out.println("代理主题:"+proxySubject.request());
	}
}

静态代理:

IUserManager.java

package com.xbmu.b.staticproxy;

public interface IUserManager {
	void addUser(String username,String passwd);
	void deleteUser(String username,String passwd);
	void modifyUser(String username,String passwd);
	String findUser(String username);
}

UserManagerImpl.java

package com.xbmu.b.staticproxy;

public class UserManagerImpl implements IUserManager {

	@Override
	public void addUser(String username, String passwd) {
		System.out.println("这是UserManagerImpl类中的addUser方法");
	}

	@Override
	public void deleteUser(String username, String passwd) {
		System.out.println("这是UserManagerImpl类中的deleteUser方法");

	}

	@Override
	public void modifyUser(String username, String passwd) {
		System.out.println("这是UserManagerImpl类中的modifyUser方法");
	}

	@Override
	public String findUser(String username) {
		System.out.println("这是UserManagerImpl类中的findUser方法");
		return "btt";
	}

}

UserManagerProxy.java

package com.xbmu.b.staticproxy;

public class UserManagerProxy implements IUserManager {

	private IUserManager userManager;
	public UserManagerProxy() {
		super();
	}
	public UserManagerProxy(IUserManager userManageImpl) {
		super();
		if(userManager == null){
			this.userManager = userManageImpl;
		}
	}
	@Override
	public void addUser(String username, String passwd) {
		checkSecurity();
		userManager.addUser(username, passwd);

	}

	@Override
	public void deleteUser(String username, String passwd) {
		checkSecurity();
		userManager.deleteUser(username, passwd);

	}

	@Override
	public void modifyUser(String username, String passwd) {
		checkSecurity();
		userManager.modifyUser(username, passwd);

	}

	@Override
	public String findUser(String username) {
		checkSecurity();
		userManager.findUser(username);
		return "bitaotao";
	}
	private void checkSecurity(){
		System.out.println("检查用户信息");
	}

}

App.java

package com.xbmu.b.staticproxy;

public class App {
	public static void main(String[] args) {
		IUserManager userManager = new UserManagerImpl();
		userManager.addUser("btt", "123");
		System.out.println("==========================");
		IUserManager userManagerProxy = new UserManagerProxy(userManager);
		userManagerProxy.addUser("btt", "123");
	}
}

JDK动态代理:

IUserManager.java

package com.xbmu.c.jdkProxy;

public interface IUserManager {
	void saveUser(String username,String password);
	void updateUser(String username,String password);
	void deleteUser(String username);
	String findUser(String username);
}

UserManagerImpl.java

package com.xbmu.c.jdkProxy;

public class UserManagerImpl implements IUserManager{

	@Override
	public void saveUser(String username, String password) {
		System.out.println("UserManagerImpl---saveUser");

	}

	@Override
	public void updateUser(String username, String password) {
		System.out.println("UserManagerImpl---updateUser");

	}

	@Override
	public void deleteUser(String username) {
		System.out.println("UserManagerImpl---deleteUser");
	}

	@Override
	public String findUser(String username) {
		System.out.println("UserManagerImpl---findUser");
		return username;
	}

}

JdkProxy.java

package com.xbmu.c.jdkProxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**Aspect(切面): 通知要放置到一个类中,那么该类就是切面,JdkProxy*/
public class JdkProxy implements InvocationHandler {

	Object userManage = null;

	/**
	 * 百度解释:
	 *	Weaving(织入):
	 *	织入,AOP术语。把切面(aspect)连接到其它的应用程序类型或对象上,
	 *  并创建一个被通知 (advised)的对象,这样的行为叫做织入。
	 * Weaving(织入):
	 *  是指把切面应用到目标对象来创建新的代理对象的过程.切面在指定的连接点织入到目标对象。
	 *  织入相当于将目标对象和代理对象关联起来
	 * */
	public Object createProxyInstance(Object userManage) {
		//将真实对象传给代理
		this.userManage = userManage;
	     /*
	      * 第一个参数设置代码使用的类加载器,一般采用跟目标类相同的类加载器
	      * 第二个参数设置代理类实现的接口,跟目标类使用相同的接口
	      * 第三个参数设置回调对象,当代理对象的方法被调用时,会调用该参数指定对象的invoke方法
	      */
		return Proxy.newProxyInstance(this.userManage.getClass().getClassLoader(),
				                     this.userManage.getClass().getInterfaces(),
				                     this);
	}

	/**
     * @param proxy   目标对象的代理类实例
     * @param method  对应于在代理实例上调用接口方法的Method实例
     * @param args 传入到代理实例上方法参数值的对象数组
     * @return 方法的返回值 没有返回值时是null
     */
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		/**
		 * Pointcut(切入点):目标对象中存在多个方法,只需要对目标对象中多个方法的某些方法进行拦截,
		 *                 此时该操作,就叫做切入点
		 * */
		if(method.getName().startsWith("save") || method.getName().startsWith("find")){
			checkSecurity();
		}
		System.out.println("代理类:"+proxy.getClass());
		System.out.println("方法的名称:"+method.getName());
		if(args!=null && args.length>0){
			for(Object arg:args){
				System.out.println("方法的参数:"+arg);
			}
		}
		//调用目标对象的方法
		Object returnValue = method.invoke(this.userManage, args);
		System.out.println("方法的返回值:"+returnValue);
		return returnValue;
	}

	/**Advice(通知):切入点要做的事情,就是通知(一般指的是方法)*/
	public void checkSecurity(){
		System.out.println("开始进行安全检查...");
	}
}

App.java

package com.xbmu.c.jdkProxy;

public class App {
	public static void main(String[] args) {
		IUserManager userManager = new UserManagerImpl();
//		userManager.saveUser("zhangsan", "123");

		JdkProxy jdkProxy = new JdkProxy();
		IUserManager userManageProxy = (IUserManager) jdkProxy.createProxyInstance(userManager);
		userManageProxy.saveUser("lisi", "456");
		System.out.println("/***********************************/");
		String user = userManageProxy.findUser("wangwu");
		System.out.println("查询用户:"+user);
		System.out.println("/***********************************/");
		userManageProxy.updateUser("zhaoliu", "789");

	}
}

使用cglib生产代理:

CGlib是一个强大的,高性能,高质量的Code生成类库。它可以在运行期扩展Java类与实现Java接口。

CglibProxy.java

package com.xbmu.d.cglibProxy;

import java.lang.reflect.Method;

import net.sf.cglib.core.Signature;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

/**切面*/
public class CglibProxy implements MethodInterceptor {

	private Object userManager = null;

	/**织入:将相当于将目标对象和代理对象关联起来*/
	public Object createProxyInstance(Object userManage) {
		this.userManager = userManage;
		Enhancer enhancer = new Enhancer();
		//设置目标对象的父类
		enhancer.setSuperclass(this.userManager.getClass());
		//开始调用回调函数,调用intercept的方法
		enhancer.setCallback(this);
		//创建代理对象
		return enhancer.create();
	}

	 /**
	    * @param obj  目标对象代理类的实例
	    * @param method 代理实例上调用父类方法的Method实例
	    * @param args  传入到代理实例上方法参数值的对象数组
	    * @param methodProxy 使用它调用父类的方法
	    * @return
	    * @throws Throwable
	    */
	public Object intercept(Object proxy, Method method, Object[] args,
			MethodProxy methodPrxoy) throws Throwable {
		/**
		 * Pointcut(切入点):目标对象中存在多个方法,只需要对目标对象中多个方法的某些方法进行拦截,
		 *                 此时该操作,就叫做切入点
		 * */
		if(method.getName().startsWith("save") || method.getName().startsWith("find")){
			checkSecurity();
		}
		System.out.println("代理类:"+proxy.getClass());
		System.out.println("方法的名称:"+method.getName());
		if(args!=null && args.length>0){
			for(Object arg:args){
				System.out.println("方法的参数:"+arg);
			}
		}
		//methodPrxoy方法的使用
		Signature signature = methodPrxoy.getSignature();//获取签名
		System.out.println("methodPrxoy:"+signature.getName() + "      "
				               + signature.getReturnType() + "       " + signature.getArgumentTypes());

		//调用目标对象的方法
		Object returnValue = method.invoke(this.userManager, args);
		System.out.println("方法的返回值:"+returnValue);
		return returnValue;
	}

	/**Advice(通知):切入点要做的事情,就是通知(一般指的是方法)*/
	public void checkSecurity(){
		System.out.println("开始进行安全检查...");
	}
}

App.java

package com.xbmu.d.cglibProxy;

public class App {
	public static void main(String[] args) {
		/**目标对象:表示访问的真实对象*/
		IUserManager userManager = new UserManagerImpl();
		userManager.saveUser("张三", "123");
		/****************************************************/
		//使用jdk代理对象访问
		/**
		 * 代理对象:在访问真实对象的前后可以添加业务逻辑,添加业务逻辑的类,称之为代理对象,
		 * 简而言之,通过代理对象来访问真实对象
		 */
		CglibProxy cglibProxy = new CglibProxy();
		IUserManager userManageProxy = (IUserManager) cglibProxy.createProxyInstance(userManager);
		/**joinpoint(连接点):程序访问目标的方法,就是连接点,saveUser,findUser,updateUser*/
		userManageProxy.saveUser("李四", "456");
		String user = userManageProxy.findUser("赵六");
		System.out.println("查询用户:"+user);
		System.out.println("/**********************************/");
		userManageProxy.updateUser("王五", "789");

		System.out.println("/**********************************/");

	}
}

AOP中的概念以及代理总结:

Aspect(切面): 是通知和切入点的结合,通知和切入点共同定义了关于切面的全部内容---它的功能、在何时和何地完成其功能

joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因spring只支持方法类型的连接点.

Pointcut(切入点):所谓切入点是指我们要对哪些joinpoint进行拦截的定义.

通知定义了切面的”什么”和”何时”,切入点就定义了”何地”.

Advice(通知):所谓通知是指拦截到joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)

Target(目标对象):代理的目标对象

Weaving(织入):是指把切面应用到目标对象来创建新的代理对象的过程.切面在指定的连接点织入到目标对象

Introduction(引入):在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field.

spring在运行期创建代理,不需要特殊的编译器.

spring有两种代理方式:

1.若目标对象实现了若干接口,spring使用JDK的java.lang.reflect.Proxy类代理。

2.若目标对象没有实现任何接口,spring使用CGLIB库生成目标对象的子类。

使用该方式时需要注意:

1.对接口创建代理优于对类创建代理,因为会产生更加松耦合的系统。对类代理是让遗留系统或无法实现接口的第三方类库同样可以得到通知,这种方式应该是备用方案。

2.标记为final的方法不能够被通知。spring是为目标类产生子类。任何需要

被通知的方法都被复写,将通知织入。final方法是不允许重写的。

spring只支持方法连接点:不提供属性接入点,spring的观点是属性拦截破坏了

封装。面向对象的概念是对象自己处理工作,其他对象只能通过方法调用的得到的

结果。

时间: 2024-10-06 22:57:27

重温Spring之旅5——AOP代理对象、JDK动态代理、使用cglib生产代理的相关文章

深入探索spring技术内幕(六): JDK动态代理和cglib生成代理

[ JDK生成代理 ] JDK中给我们提供了一个Proxy类可以动态的给我们生成代理. 假定我们要做一个权限管理系统, 需要控制用户对某一个方法的访问. 如果user为null, 那么不让用户访问save方法. ① 接口类: PersonService public interface PersonService { public void save(); } ② 实现类: PersonServiceImpl public class PersonServiceImpl implements P

动态代理:JDK动态代理和CGLIB代理的区别

代理模式:代理类和被代理类实现共同的接口(或继承),代理类中存有指向被代理类的索引,实际执行时通过调用代理类的方法.实际执行的是被代理类的方法. 而AOP,是通过动态代理实现的. 一.简单来说: JDK动态代理只能对实现了接口的类生成代理,而不能针对类 CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法(继承) 二.Spring在选择用JDK还是CGLiB的依据: (1)当Bean实现接口时,Spring就会用JDK的动态代理 (2)当Bean没有实现接口时,Spring使

Java之代理(jdk静态代理,jdk动态代理,cglib动态代理,aop,aspectj)

一.概念 代理是什么呢?举个例子,一个公司是卖摄像头的,但公司不直接跟用户打交道,而是通过代理商跟用户打交道.如果:公司接口中有一个卖产品的方法,那么公司需要实现这个方法,而代理商也必须实现这个方法.如果公司卖多少钱,代理商也卖多少钱,那么代理商就赚不了钱.所以代理商在调用公司的卖方法后,加上自己的利润然后再把产品卖给客户.而客户部直接跟公司打交道,或者客户根本不知道公司的存在,然而客户最终却买到了产品. 专业点说:代理模式是对象的结构型模式,代码模式给某一个对象提供代理,并由代理对象控制原对象

设计模式---JDK动态代理和CGLIB代理

Cglig代理设计模式 /*测试类*/ package cglibProxy; import org.junit.Test; public class TestCglib { @Test public void test1(){ CglibProxy cglibProxy=new CglibProxy(); UserServiceImpl userServiceImpl = (UserServiceImpl)cglibProxy.createProxyInstance(new UserServi

关于JDK动态代理和CGLIB动态代理

1. 代理模式 一句话总结:为其他对象提供一种代理以控制对这个对象的访问.千篇一律的介绍:代理模式是常用的java设计模式,他的特征是代理类与委托类(或目标类)有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务. 按照代理的创建时期,代理类可以分为两种. 静态代理:由程序员创建或特定工具

AOP、静态代理、JDK动态代理、CGLIB动态代理、Spring实现AOP、IOC+AOP

一.为什么需要代理模式 假设需实现一个计算的类Math.完成加.减.乘.除功能,如下所示: 1 package com.zhangguo.Spring041.aop01; 2 3 public class Math { 4 //加 5 public int add(int n1,int n2){ 6 int result=n1+n2; 7 System.out.println(n1+"+"+n2+"="+result); 8 return result; 9 } 1

【Spring】AOP之JDK动态代理和CGLib动态代理

林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 一.JAVA动态代理  1.1 代理模式         代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务. 按照代理的创

spring aop原理 JDK动态代理和CGLIB动态代理

Spring的两大特性是IOC和AOPIOC负责将对象动态的注入到容器,从而达到一种需要谁就注入谁,什么时候需要就什么时候注入的效果.理解spring的ioc也很重要.但是今天主要来和大家讲讲aop.AOP 广泛应用于处理一些具有横切性质的系统级服务,AOP 的出现是对 OOP 的良好补充,用于处理系统中分布于各个模块的横切关注点,比如事务管理.日志.缓存等等. AOP实现的关键在于AOP框架自动创建的AOP代理.AOP代理主要分为静态代理和动态代理, 静态代理的代表为AspectJ:动态代理则

Spring 静态代理+JDK动态代理和CGLIB动态代理

代理分为两种:静态代理 动态代理 静态代理:本质上会在硬盘上创建一个真正的物理类 动态代理:本质上是在内存中构建出一个类. 如果多个类需要进行方法增强,静态代理则需要创建多个物理类,占用磁盘空间.而动态代理则是在内存中创建,不会对磁盘进行影响. 静态代理和JDK动态代理需要有接口. CGLIB动态代理无需有接口的情况下进行代理.实质:内存中构建出了目标类型的子类. JDK动态代理是JDK提供的,CGLIB动态代理是Spring提供的. 代理模式的三个组件:抽象主题 真实主题 代理主题 静态代理: