为了面试,记录一下spring的基础
什么是IOC
IOC(控制反转):将由spring 创建对象实例
什么是DI
DI (依赖注入),类似于设计原则中依赖倒置
is a (是一个) : 泛化(继承)
has a(有一个) : 依赖
依赖:一个对象需要使用另一个对象
注入:通过setter 方法进行另一个对象的实例
private ADao a = new AImpl(); // 耦合
private ADao a; // 解耦,不知道实现对象,可以通过setter 方法注入
AOP
AOP 面向切面编程
AOP 实现原理
- AOP 底层将采用代理机制进行实现。
- 接口 + 实现类 : spring 采用jdk 的动态代理 Proxy
- 实现类 : spring 采用 cglib 字节码的增强
经典应用:事务管理、性能检测,缓存
AOP 术语
target 目标类 ,需要被代理的类。 例如 UserService
JoinPoint(连接点):所谓连接点是指那些可能被拦截的方法。例如,所有的方法。
PointCut 切入点:已经被增强的连接点。例如 addUser()
advice 通知增强,例如 after , before
Weaving(织入):是指把增强advice应用到目标对象来创建新的代理对象的过程。
proxy:代理类
aspect(切面):是切入点pointcut和通知advice的结合
JDK 动态代理
通过jdk 动态代理实现 切面编程
// 目标类
public interface UserService {
public void addUser();
public void updateUser();
public void deleteUser();
}
// 实现类 (所有方法)
public class UserServiceImpl implements UserService{
@Override
public void addUser() {
System.out.println("addUser");
}
@Override
public void updateUser() {
System.out.println("updateUser");
}
@Override
public void deleteUser() {
System.out.println("deleteUser");
}
}
// 切面
public class MyAspect {
public void before(){
System.out.println("before");
}
public void after(){
System.out.println("after");
}
}
package com.longchuang.aop;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class MyBeanFactory {
public static UserService create(){
// 1,目标类
UserService userService = new UserServiceImpl();
// 2,切面类
MyAspect myAspect = new MyAspect();
// 3,代理类:将目标类和切面类(通知) 结合 --》 切面
/**
* Proxy.newProxyInstance()
* 参数1: loader ,类加载器,动态代理运行时创建,任何类都需要类加载器将其加载到内存。
* 一般情况:当前类.class.getClassLoader();
* 目标类.getClass.getCla...
* 参数2:Class[] interfaces 代理类需要实现的所有接口
* 方式1:目标类实例.getClass.getInterfaces(); // 注意:只能获得自己接口,不能获得父元素接口
* 方式2:new Class[]{UserService.class}
*
* 参数3:InvocationHandler 处理类,接口,必须进行实现
* 参数31:Object proxy : 代理对象
* 参数32: Method method : 代理对象当前执行的方法描述对象(反射)
* 参数33:Object[] args : 方法实际参数
*/
UserService proxyService = (UserService)Proxy.newProxyInstance(MyBeanFactory.class.getClassLoader(),
userService.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//前方法
myAspect.before();
// 执行目标方法
Object invoke = method.invoke(userService, args);
//后方法
myAspect.after();
return invoke;
}
});
return proxyService;
}
}
cglib
- 没有借口,只有实现类
- 采用字节码增强框架,运行时, 创建目标类子类,从而对目标类进行增强
// 这里除去UserService借口类,还有就是此实现类不一致
public class MyBeanFactory {
public static UserServiceImpl create(){
// 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 接口
* intercep() 等效jdk invoke()
* 参数1、参数2、参数3 : 以invoke 一样
*
*/
enhancer.setCallback(new MethodInterceptor){
@Override
public Object intercep(Object proxy , Method method , Object[] args , MethodProxy proxyMethod){
//前
myAspect.before();
// 执行目标类方法
Object obj = method.invoke(userService,args);
//后
myAspect.after();
return obj;
}
}
UserServiceImpl proxyService = (UserServiceImpl)enhancer.create();
return proxyService;
}
}
aop 通知类型
spring 按照通知Advice 在目标方法的连接点位置,可以分为5类
- 前置通知
- 后置通知
- 环绕通知
- 抛出异常通知
- 引介通知(很少用)
AspectJ 实现 AOP
切入点表达式 execution ( com.sample.service.impl…*. (…))
- execution(): 表达式主体。
- 第一个*号:表示返回类型, *号表示所有的类型。
- 包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,com.sample.service.impl包、子孙包下所有类的方法。
- 第二个*号:表示类名,*号表示所有的类。
- *(…):最后这个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数
AspectJ 通知类型
- before 前置通知(应用于数据校验)
- afterReturning 后置通知(常规数据处理)
- around 环绕通知
- afterThrowing 掏出异常通知
- after 最终通知
实战
@Slf4j
@Aspect
@Component
public class MyAspect {
@Pointcut("execution(* city.thesixsectorteam.wheelworld.area.controller.TestController1.*(..))")
public void pointcut2(){
}
@Before("pointcut2()")
public void tes2t(JoinPoint joinPoint){
System.out.println("test");
}
}
当我调用TestController1 中的接口时,就会打印 test