几个重要概念
Dependency Injection (DI)
from wiki:
An object receives other objects that it depends on, called dependencies; The receiving object is called a client and the passed-in (injected) object is called a service. The code that passes the service to the client is called the injector;
why: to achieve separation of concerns (“use” & “construction”)
A client who wants to call some services should not have to know how to construct those services. Instead, the client delegates to (委托给) external code (the injector).
Inversion of Control (IoC)
from wiki:
In IoC, custom-written portions of a computer program receive the flow of control from a generic framework. In traditional programming, the custom code that expresses the purpose of the program calls into reusable libraries to take care of generic tasks, but with IoC, it is the framework that calls into the custom or task-specific code.
why: to increase modularity of the program and make it extensible
e.g. The general concept is also related to event-driven programming in that it is often implemented using IoC so that the custom code is commonly only concerned with the handling of events, whereas the event loop and dispatch of events/messages is handled by the framework or the runtime environment.
Aspect-oriented Programming (AOP)
from wiki
It dose so by adding additional behaviour to existing code (an advice) without modifying the code itself, instead separately specifying which code is modified via a “pointcut” specification, such as “log all function calls when the function's name begins with 'set'”. This allows behaviours that are not central to the business logic to be added to a program without cluttering the code core to the functionality.
why: increase modularity by allowing separation of cross-cutting concerns
重点关注对象
- Bean
- BeanFactory & ApplicationContext
- AOP
Bean 的生命周期
BeanFactory
ApplicationContext
关于线程安全
- Spring中的单例bean不是线程安全的
- 大部分时候Spring的bean是无状态的(不存储数据)如DAO类,所以也是线程安全的
- 当Bean有状态时,一般采用ThreadLocal的方式处理解决线程安选问题(空间换时间,锁-时间换空间)
关于自动装配
- 什么是自动装配:Bean之间的依赖关系,由Spring容器/框架来负责将引用赋予各个对象
- 方式: xml配置,@Autowired 注解配置等
- 什么是循环依赖,如何解决?: A引用了B,B引用了A;三级缓存来解决
- 一级缓存的解决方式: 在A被newInstance但还没有进行属性填充的时候直接放入缓存中;A进行属性填充,需要B时去newInstance B并把此时的B放进缓存中,再去填充B的属性时,正好可以拿到在缓存中还没有进行完全属性填充的A,之后B就被完全实例化了,反过来再继续对A进行属性填充就完成了。
- 但对于代理对象和AOP应用:e.g. 工厂对象,当要获取的对象是需要工厂对象生产时,通过getEarlyBeanReference逻辑将工厂对象放进三级缓存中;再获取该对象时,是由工厂对象getObject拿到的;属性填充时,getSingleton()从三个缓存中寻找该对象,如果一二级有,直接取走,如果对象是三级缓存中的对象就从三级缓存中获取后并删除工厂对象把实际的对象放进二级缓存中。
AOP
AOP核心技术的实现是动态代理的使用
- 何为代理?:有一个接口,你去实现了这个接口,用的时候就 new Impl() 去调用;使用代理,你可以用代理去做这件事,而不是写一个类去实现这个接口并创建该类实例,如
@Test
public void test_proxy_class(){
IUserService userService = (IUserService) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{IUserService.class}, (proxy, method, args) -> "你被代理了!");
String result = userService.queryUserInfo();
System.out.println(result);
}
如果可以代理掉所有类的方法,就可以做一个方法拦截器,给所有被代理的方法加一些自定义处理如加日志,统计监控等等 (这也是为什么要用代理模式的原因,可以为调用方提供统一的调用方式,但是在调用进行前后做一些统一的处理)
JDK动态代理
public class JdkDynamicAopProxy implements AopProxy, InvocationHandler{
private final AdvisedSupport advised;
public JdkDynamicAopProxy(AdvisedSupport advised) {
this.advised = advised;
}
@Override
public Object getProxy() {
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), advised.getTargetSource().getTargetClass(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
if (advised.getMethodMatcher().matches(method, advised.getTargetSource().getTarget().getClass())) {
MethodInterceptor methodInterceptor = advised.getMethodInterceptor();
//ReflectiveMethodInvocation入参的包装信息,提供了入参的对象:目标对象方法入参等
return methodInterceptor.invoke(new ReflectiveMethodInvocation(advised.getTargetSource().getTarget(), method, args));
}
return method.invoke(advised.getTargetSource().getTarget(), args);
}
}
Cglib动态代理
public class Cglib2AopProxy implements AopProxy{
private final AdvisedSupport advised;
public Cglib2AopProxy(AdvisedSupport advised) {
this.advised = advised;
}
@Override
public Object getProxy(){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(advised.getTargetSource().getTarget().getClass());
enhancer.setInterfaces(advised.getTargetSource().getTargetClass());
enhancer.setCallback(new DynamicAdvisedInterceptor(advised));
return enhancer.create();
}
private static class DynamicAdvisedInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
CglibMethodInvocation methodInvocation = new CglibMethodInvocation(advised.getTargetSource().getTarget(), method, objects, methodProxy);
if (advised.getMethodMatcher().matches(method, advised.getTargetSource().getTarget().getClass()))
{
return advised.getMethodInterceptor().invoke(methodInvocation);
}
return methodInvocation.proceed();
}
}
private static class CglibMethodInvocation extends ReflectiveMethodInvocation {
@Override
public Object proceed() throws Throwable {
return this.methodProxy.invoke(this.target, this.arguments);
}
}
}