Spring(2)之 (AOP 面向切面编程)(AOP目录)

Spring Core:

Spring的核心功能即IOC容器,解决对象的创建及对象之间的依赖关系

Spring WEB:

Spring对WEB模块的支持

Spring AOP: 面向切面编程

  1. AOP的概述
  2. AOP的底层实现
  3. Spring AOP开发
    (网址: https://blog.csdn.net/qq_41029923/article/details/84230164
  4. 使用 AspectJ实现 AOP
    (网址: https://blog.csdn.net/qq_41029923/article/details/84250237
  5. Spring JDBC Template的使用
    (网址: https://blog.csdn.net/qq_41029923/article/details/84291336
     

1. AOP编程基本概念:
AOP: Aspect Object Programming 面向切面编程
      功能:让关注点代码与业务代码分离
关注点: 重复的代码(方法)
切面: 关注点形成的类
面向切面编程就是指对很多功能重复的代码的抽象,再在运行时向业务方法中动态的植入“切面类代码”;
切入点: 通过切入点表达式,指定拦截哪些类的哪些方法,给指定的类在运行时植入切面类代码
 

2. 代理模式:
代理模式是一种设计模式,提供了对目标对象的另外的访问方式即通过代理对象访问目标对象;
好处: 可以在目标对象实现的基础上(即不改变目标对象的代码),增加额外的功能——扩展目标对象的功能

  1. 静态代理
    eg:保存数据到数据库,Dao直接保存; 添加事务;代理对象要实现与目标对象一样的接口;
    优点: 可以做到在不修改目标对象功能的前提下(即目标对象代码不做更改),对目标对象进行扩展;
    缺点: 代理对象要实现与目标对象一样的接口,会有很多代理类,一旦接口增加方法,目标对象和代理对象都需要维护(即因为两者都实现了此接口,所以代码都要做更改)
    解决方式: 使用代理工厂、动态代理;
  2. 动态代理(也叫JDK代理、接口代理)
    目标对象一定要实现接口, 否则不能使用动态代理;
    代理对象不需要实现接口;
    代理对象的生成使用到 JDK API,动态的在内存中创建对象 (即 class $Proxy0 implements XXX);
    API中:
    Proxy
    public static Object newProxyInstance(
          ClassLoader loader, //指定当前目标对象的使用类的加载器
          Class<?> [] interfaces,//目标对象实现的接口类型
          InvocationHandler h //事件处理器
    )
  3. Cglib代理(子类代理)
    子类代理,在内存中构建一个子类对象从而实现对目标对象的扩展,Cglib代理许多AOP框架使用;
    步骤:
          应用 .jar文件—Spring Core包中包含;
          在内存中动态创建目标对象的子类;
          目标对象不能是 final;
          目标对象方法时 final、static,则不会拦截;

在 Spring AOP 编程中:
动态代理:目标对象要实现接口,代理对象不需要实现接口(直接在代理对象中添加代码);
Cglib代理:目标对象不需要实现接口(代理对象实现了 MethodInterceptor 接口),(直接在代理对象中添加代码);
如果加入容器中的目标对象实现了接口,会自动使用JDK代理;
如果目标对象 没有 实现接口(且目标对象不是 final),会自动使用 Cglib代理;

 
 

eg:1. 静态代理
接口IUserDao.java中有一个方法; UserDao.java是目标对象:实现IUserDao接口,实现里面的方法;想添加事务,若直接在目标对象中添加, 这样不好,所以要新增一个代理对象UserDaoProxy; UserDaoProxy.java是代理对象,要实现与目标对象 UserDao一样的接口 IUserDao。代理对象中添加目标对象,添加接口,因为目标对象实现了接口,这样可以通过添加接口来添加实现类,来调用目标对象中的方法,在调用方法前后添加事务即可;)

1.1 IUserDao.java(接口)

public interface IUserDao{
	public void save() throws Exception;
}

1.2 UserDao.java(目标对象)
(UserDao.java中实现IUserDao接口,实现里面的方法;想添加事务,若直接在目标对象中添加, 这样不好)

public class UserDao implements IUserDao{
	public void save() throws Exception{
		//System.out.println("----开始事务----");
		System.out.println("----数据已保存----");
		//System.out.println("----提交事务----");
	}
}

1.3 UserDaoProxy.java(代理对象_静态代理)
(代理对象(UserDaoProxy)要实现与目标对象(UserDao)一样的接口(IUserDao)。代理对象中添加目标对象,添加接口,因为目标对象实现了接口,这样可以调用目标对象中的方法,在调用方法前后添加事务即可;)

public class UserDaoProxy implements IUserDao{
	private IUserDao target;
	public UserDaoProxy(IUserDao target){
		this.target=target;
	}
	public void save() throws Exception{
		System.out.println("----开始事务----");
		target.save();
		System.out.println("----提交事务----");
	}
}

1.4 Test.java
(通过接口 IUserDao 生成一个目标对象 target,生成一个代理对象 proxy将 target传入,代理对象调用方法)

public class Test{
	public static void main(String[] args) {
		IUserDao target=new UserDao();//目标对象
		UserDaoProxy proxy=new UserDaoProxy(target);//代理对象
		try{
			proxy.save();
		}catch(Exception e){
			e.printStackTrace();
		}
	}
}

运行结果:
在这里插入图片描述
eg:2. 动态代理
(若接口中增加方法,目标对象实现了接口所以也要增加方法,但代理对象中不需要再增加方法;直接在测试类中调用增加的方法即可)
2.1 IUserDao.java(接口)

public interface IUserDao{
	public void save() throws Exception;
	
	public void update() throws Exception;
}

2.2 UserDao.java(目标对象)
(UserDao.java中实现IUserDao接口,实现里面的方法;想添加事务,若直接在目标对象中添加, 这样不好)

public class UserDao implements IUserDao{
	public void save() throws Exception{
		//System.out.println("----开始事务----");
		System.out.println("----数据已保存----");
		//System.out.println("----提交事务----");
	}
	
	public void update() throws Exception{
		System.out.println("----数据已修改----");
	}
}

2.3 ProxyFactory.java
(代理工厂 ProxyFactory中有目标对象,private IUserDao target,因为目标对象所实现的接口不止有IUserDao,IUserDao换成Object会更好;目标对象要实现接口,代理对象不需要实现接口(直接在代理对象中添加代码));

public class ProxyFactory{
	private Object target;//目标对象
	public ProxyFactory(Object target){
		this.target=target;
	}
	public Object getProxyInstance(){//生成代理对象
		Proxy.newProxyInstance(
			target.getClass().getClassLoader(),
			target.getClass().getInterfaces(),
			new InvocationHandler(){
				public Object invoke(Object proxy,Method method,Object[] args) throws Exception{
					System.out.println("开始事务");
					Object result=method.invoke(target,args);//调用目标对象方法
					System.out.println("提交事务");
					return result;
				}
			}
		);
	}
}

2.4 Test.java

public class Test{
	public static void main(String[] args) {
		//目标对象
		UserDao target=new UserDao();
		//代理对象
		IUserDao proxy=(IUserDao)new ProxyFactory(target).getProxyInstance();
		//执行
		try{
			proxy.save();
			
			proxy.update();
		}catch(Exception e){
			e.printStackTrace();
		}
		System.out.println(proxy.getClass());
	}
}

运行结果:
在这里插入图片描述
接口中新增方法后运行结果:
在这里插入图片描述
eg:3. Cglib 代理
3.1 IUserDao.java(接口)

public interface IUserDao{
	public void save() throws Exception;
	public void update() throws Exception;
}

3.2 UserDao.java(目标对象)
(UserDao.java不需要实现IUserDao接口)

public class UserDao{ //不能final(public final class UserDao)
	public void save() throws Exception{ //不能是final、static(public final、static void save())
		System.out.println("----数据已保存----");
	}
	public void update() throws Exception{
		System.out.println("----数据已修改----");
	}
}

3.3 ProxyFactory.java
(代理工厂 ProxyFactory中有目标对象,private IUserDao target,因为目标对象所实现的接口不止有IUserDao,IUserDao换成Object会更好;)

/*Cglib子类代理工厂(对UserDao在内存中创建一个代理)*/
public class ProxyFactory implements MethodInterceptor{
	private Object target;//目标对象
	public ProxyFactory(Object target){
		this.target=target;
	}

	//代理对象
	public Object getProxyInstance(){
		//1.工具类
		Enhancer en=new Enhancer();
		//2.设置父类
		en.setSuperclass(target.getClass());
		//3.设置回调方法(调用下方的intercept方法)
		en.setCallback(this);
		//4.创建代理对象
		return en.create();
	}
	public Object intercept(Object arg0,Method arg1,Object[] arg2,MethodProxy arg3) throws Throwable{
		System.out.println("开启事务------");
		//执行目标对象的方法
		Object resultValue=method.invoke(target,arg2);
		System.out.println("结束事务");
		return resultValue;
	}
}

3.4 Test.java

public class Test{
	public static void main(String[] args) {
		//目标对象
		UserDao target=new UserDao();
		//代理对象
		IUserDao proxy=(IUserDao)new ProxyFactory(target).getProxyInstance();
		//执行
		try{
			proxy.save();
		}catch(Exception e){
			e.printStackTrace();
		}
		System.out.println(proxy.getClass());
	}
}

运行结果:
在这里插入图片描述
目标对象 UserDao 是final的运行结果:
(目标对象不能是 final)
会报错
目标对象中的方法 save 是final、static的运行结果:
(目标对象的方法如果是 final、static,则不会拦截(没有“开始事务、结束事务”))
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值