Spring Core:
Spring的核心功能即IOC容器,解决对象的创建及对象之间的依赖关系
Spring WEB:
Spring对WEB模块的支持
Spring AOP: 面向切面编程
- AOP的概述
- AOP的底层实现
- Spring AOP开发
(网址: https://blog.csdn.net/qq_41029923/article/details/84230164 ) - 使用 AspectJ实现 AOP
(网址: https://blog.csdn.net/qq_41029923/article/details/84250237 ) - Spring JDBC Template的使用
(网址: https://blog.csdn.net/qq_41029923/article/details/84291336 )
1. AOP编程基本概念:
AOP: Aspect Object Programming 面向切面编程
功能:让关注点代码与业务代码分离
关注点: 重复的代码(方法)
切面: 关注点形成的类
面向切面编程就是指对很多功能重复的代码的抽象,再在运行时向业务方法中动态的植入“切面类代码”;
切入点: 通过切入点表达式,指定拦截哪些类的哪些方法,给指定的类在运行时植入切面类代码
2. 代理模式:
代理模式是一种设计模式,提供了对目标对象的另外的访问方式即通过代理对象访问目标对象;
好处: 可以在目标对象实现的基础上(即不改变目标对象的代码),增加额外的功能——扩展目标对象的功能
- 静态代理
eg:保存数据到数据库,Dao直接保存; 添加事务;代理对象要实现与目标对象一样的接口;
优点: 可以做到在不修改目标对象功能的前提下(即目标对象代码不做更改),对目标对象进行扩展;
缺点: 代理对象要实现与目标对象一样的接口,会有很多代理类,一旦接口增加方法,目标对象和代理对象都需要维护(即因为两者都实现了此接口,所以代码都要做更改)
解决方式: 使用代理工厂、动态代理; - 动态代理(也叫JDK代理、接口代理)
目标对象一定要实现接口, 否则不能使用动态代理;
代理对象不需要实现接口;
代理对象的生成使用到 JDK API,动态的在内存中创建对象 (即 class $Proxy0 implements XXX);
API中:
Proxy
public static Object newProxyInstance(
ClassLoader loader, //指定当前目标对象的使用类的加载器
Class<?> [] interfaces,//目标对象实现的接口类型
InvocationHandler h //事件处理器
) - 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,则不会拦截(没有“开始事务、结束事务”))