1、什么是控制反转(IOC)?
IOC:根据javase,我们直接在对象内部通过new进行创建对象,是程序主动去创建对象。而ioc是有个专门容器来创建这些对象。是ioc容器控制了对象,即控制权的转移,应用程序本身不负责依赖对象的创建和维护,而是由外部容器负责创建和维护。传统程序是我们在类内部主动创建依赖对象,导致类之间的高耦合。Ioc设计的好处是松耦合,增加灵活性。Spring容器创建好对象,存储到一个容器里,需要使用对象的时候,直接从容器中取出需要的对象即可。
IOC的原理:工厂模式加反射机制,根据配置文件给出的类名动态的生成对象,要生产的对象都在配置文件中给出定义。
2、BeanFactory和ApplicationContext有什么区别?
前者是基础类型的IOC容器,含有bean集合的工厂类,采用懒加载的形式,容器启动后不会创建bean对象,只有当使用某个bean时,才对该bean进行加载实例化。ApplicationContext在前者的基础上,增加了更高级的功能,提供了如下功能:访问资源(如url和文件,比如其扩展类ClassPathXmlApplicationContext),支持aop功能,事务处理,在容器启动时便完成了所有bean的创建(预加载)
3、如何用注解的方式配置spring?
@Autowired注解的原理是反射,通过反射获取需要注入的bean
可以将bean描述转移到组件类的内部,只需要在相关类、方法或者字段上使用注解即可,注解注入将会被容器在xml注入之前被处理,所以后者会覆盖掉前者对于同一个属性的处理结果。@controller,@Service都可以负责注册一个bean到spring的上下文中。下面是几种重要的注解类型
Bean:注解用于告诉方法,产生一个Bean对象,然后这个Bean对象交给Spring管理。产生这个Bean对象的方法Spring只会调用一次,随后这个Spring将会将这个Bean对象放在自己的IOC容器中。
@Bean和@Autowired区别:
bean注解用于在Spring上下文中注册Bean,而Autowried注解用于从Spring应用程序内容获取Bean并将其连接为另一个对象的依赖项,bean注解的方法如果有入参,则会从spring容器中根据类型注入
@Autowired 默认required属性值为true,即注入时,该bean必须已经初始化在spring容器中,否则注入失败
构造函数,@autowired @PostConstruct执行顺序
静态变量或静态语句块 -》实例变量或初始化语句块 -》Consturctor >> @Autowired >> @PostConstruct
注意@PostConstruct只有在spring环境中才有意义 否则不会执行
spring支持基于接口的直接注入:
@Autowired
private List<MyInterface> mylist; 这样可以把MyInterface的子类bean直接添加到了myList中,并且还可以用Order来指定添加顺序
@Autowired如果作用在构造器上,可以把构造器的入参注入到容器中
@Required:此注解用于bean的setter方法上。表示此属性是必须的,必须在配置阶段注入,否则会抛出BeanInitializationExcepion。@Qualifier此注解是和@Autowired一起使用的。使用此注解可以让你对注入的过程有更多的控制。
@Qualifier可以被用在单个构造器或者方法的参数上。当上下文有几个相同类型的bean,使用@Autowired则无法区分要绑定的bean,此时可以使用@Qualifier来指定名称。
@Component
public class User {
@Autowired
@Qualifier("address1")
private Address address;
...
}
容器一般都会在启动的时候实例化所有单实例bean。如果我们想要 Spring 在启动的时候延迟加载 bean,即在调用某个 bean 的时候再去初始化,那么就可以使用 @Lazy 注解。此注解只对单例bean有用
4、Spring怎么解决循环依赖的问题?
通过下面的bean生命周期可以看出,spring先将bean对象实例化(依赖构造函数),然后再设置对象属性。所以spring先用构造器实例化bean对象,将实例化结束的对象放到一个map中,所以spring先实例化A,B,C类,然后在设置对象属性的时候,A依赖B,就会从map中取出存在里面的B对象,以此类推,不会出来循环引用的问题了。
5、以BeanFactory为例,说明一个bean的生命周期:
1)容器读取bean定义的文件,并生成bean的实例。
2)给bean注入所有的属性。
3)如果有实例实现了BeanPostProcessor接口,则任何bean初始化之前都会回调这个实例的postProcessBeforeInitialization()方法,并且任何bean都会在init-method方法后执行这个实例的postProcessAfterInitialization()方法。
4)如果bean配置了init-method方法,则会执行init-method配置的方法。
5)如果bean配置了destory-method方法,则会执行destory-method配置的方法。至此整个bean的生命周期结束。
6、spring框架中用到了哪些设计模式?
工厂模式:spring容器实例化bean用到了静态工厂模式,Spring中的BeanFactory就是简单工厂模式的体现,根据传入一个唯一的标识来获得Bean对象
单例模式:spring配置文件中定义的bean默认为单例模式
适配器模式:aop中定义的三种通知类型BeforeAdvice, AfterAdvice,ThrowsAdvice实际上是借助适配器实现的,可以允许用户加入自己想要的任何一种通知类型,增强了代理方法的功能
代理模式:jdk,cglib
模板模式:如spring的事务管理器:https://zhuanlan.zhihu.com/p/125534510。事务管理器抽象类的模板方法中有begin,commit等方法,事务管理器的子类分别实现自己的begin,commit,rollback等方法。
7、什么是aop
就是运行时,动态的将代码切入到类的指定方法或指定位置上的编程思想。可以减少系统重复代码,降低耦合。Aop作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开。Aop的通知指的是拦截到目标方法后,要执行的代码,通知分为前置,后置,异常,环绕等。AOP代理分为静态代理:AspectJ和动态代理Spring AOP
aop的简单实现:https://blog.csdn.net/qq_37774171/article/details/86528612?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-86528612-blog-50753592.pc_relevant_aa2&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-86528612-blog-50753592.pc_relevant_aa2&utm_relevant_index=1
此aop的切入点是个注解,被此注解标注的方法都会被aop增强。aop五种类型的通知注解:
@Before:前置通知,在方法执行之前执行
@After:后置通知,在方法执行之后执行。在目标方法执行后(无论是否发生异常),执行的通知
@AfterRunning:返回通知,在方法返回结果后执行,可以访问到方法的返回值的
@AfterThrowing:异常通知,在方法抛出异常之后执行,可以访问到异常对象,且可以指定在出现特定异常时再执行通知代码
@Around:环绕通知,围绕着方法执行
8、动态代理
jdk动态代理和CGLIB动态代理。动态代理是在内存中生成一个代理对象,这个代理对象包含了目标对象的全部方法,并在特定的切点做了增强处理,并回调原来的方法。
jdk动态代理:通过反射来接收被代理的类,创建一个代理类,客户端通过调用代理类来调用目标类方法。在调用目标类方法的过程中可以添加前置通知和后置通知等效果。核心类有InnovationHandler接口, Proxy类。Proxy类:类的静态方法用来生成动态代理的实例。InnovationHandler接口有一个invoke方法,用来处理在动态代理类对象的方法调用,通常在该方法中实现对委托类的代理访问,每次生成动态代理对象时都要指定一个对应的调用处理器。jdk动态代理demo:
public class MyAspect {
public void before() {
System.out.println("before");
}
public void after() {
System.out.println("after");
}
}
public interface UserService {
void addUser();
void updateUser();
}
public class UserServiceImpl implements UserService {
@Override
public void addUser() {
System.out.println("addUser");
}
@Override
public void updateUser() {
System.out.println("updateUser");
}
}
public class MyBeanFactory {
public static UserService createUserService() {
//目标类
UserService userService = new UserServiceImpl();
//切面类
MyAspect myAspect = new MyAspect();
InvocationHandler invocationHandler = new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] args) throws Throwable {
myAspect.before(); // 前执行
method.invoke(userService, args); //执行目标类方法
myAspect.after(); // 后执行
return o;
}
};
UserService proxyService = (UserService) Proxy.newProxyInstance(MyBeanFactory.class.getClassLoader(),
userService.getClass().getInterfaces(), invocationHandler);
return proxyService;
}
public static void main(String[] args) {
UserService userService = MyBeanFactory.createUserService();
userService.addUser();
userService.updateUser();
}
}
标签:容器,对象,spring,基础知识,bean,注解,方法 From: https://www.cnblogs.com/MarkLeeBYR/p/17101013.html