IOC(控制反转)
平常我们new一个实例,这个实例的控制权是我们自己,而控制反转是指new实例的工作交给spring容器来做。
针对于一个接口,我们可能会写多个实现类,如果在代码中对实现类的对象进行创建,当想更换实现类时,就需要对代码进行更改,特别麻烦。
DI(依赖注入)
1.谁依赖谁?
具体对象的创建依赖于xml文件(IOC容器)。
2.谁注入,注入什么?
IOC容器的注入,在运行期间,根据xml的配置信息,将具体的对象注入到相应的bean中。
创建bean的时候,必须有一个无参构造函数,同时提供get/set方法。
Bean的生命周期:
1.通过构造器或工厂方法创建 Bean 的实例
2.为 Bean 的属性设置值和对其他 Bean 的引用
3.将 Bean 实例传递给 bean 后置处理器的 postProcessBeforeInitialization() 方法
4.调用 Bean 的初始化方法
5.将 Bean 实例传递给 bean 后置处理器的 postProcessAfterInitialization() 方法。
6.使用 Bean
7.当容器关闭时,调用 Bean 的销毁方法。
AOP(面向切面)
可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。
可以将日志记录,性能统计,安全控制,事务处理,异常处理等从业务逻辑代码中划分出来。
AOP的设计:
每个bean都会被JDK或者Cglib代理。取决于是否有接口。
每个bean都会有多个方法拦截器。拦截器分为两层:
外层由spring内核控制流程,内层拦截器是用户设置,也就是AOP。
当代理方法被调用时,先经过外层拦截器,外层拦截器根据方法的各种信息判断该方法应该执行哪些内层拦截器,内层拦截器的设计就是职责连的设计。
AOP可以分成2个部分来分析:
1.代理的创建
首先需要创建代理工厂(拦截器数组,目标对象接口数组,目标对象);
创建代理工厂时,默认会在拦截器数组尾部再增加一个默认拦截器------用于最终调用目标方法;
当调用getProxy方法的时候,会根据接口数量大于0条件返回一个代理对象(JDK or Cglib);
2.代理的调用
当对代理对象调用时,首先会触发外层拦截器;
外层拦截器根据代理配置信息创建内层拦截器链。创建过程中,会根据表达式判断当前拦截器是否匹配这个拦截器,而这个拦截器链设计模式就是职责链模式;
当整个链条执行到最后时,就会触发创建代理时那个尾部对默认拦截器,从而调用目标方法,最后返回。
SpringMVC流程图
SSM框架中常用的注解
@Controller
@Service
@RequestMapping
@Resource
@Autowired
@PathVariable
@ResponseBody
@RequestParam
@Repository
@Transactional 在service层加载事务,目的在于关于操作数据库的操作由事务来管理
@ModelAttribute
@SessionAttributes
@RequiresPermissions 权限注解
@Param
@Postmapping @RequestMapping(method = RequestMethod.POST)的缩写
@GetMapping() @RequestMapping(method = RequestMethod.GET)的缩写
Spring自定义注解步骤
1.在配置中打开AOP编程
<!-- 自定义AOP --> <aop:aspectj-autoproxy proxy-target-class="true"> <aop:include name="serviceAspect" /> </aop:aspectj-autoproxy> <bean id = "serviceAspect" class="com.thc.tenantcenter.aspect.LogAspect"></bean>
2.编写自己自定义的注解
package com.thc.tenantcenter.aspect; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited public @interface LogAnnotation { String desc() default "打印日志"; }
3.编写自己的切面实现类,就是上文所说的bean指向的路径
package com.thc.tenantcenter.aspect; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Aspect; import org.springframework.stereotype.Component; @Aspect //该注解标示该类为切面类 @Component //注入依赖 public class LogAspect { //标注该方法体为后置通知,当目标方法执行成功后执行该方法体 @AfterReturning("within(com.thc.tenantcenter..*) && @annotation(rl)") public void addLogSuccess(JoinPoint jp, LogAnnotation rl){ Object[] parames = jp.getArgs();//获取目标方法体参数 for (int i = 0; i < parames.length; i++) { System.out.println(parames[i]); } System.out.println(jp.getSignature().getName()); String className = jp.getTarget().getClass().toString();//获取目标类名 System.out.println("className:" + className); className = className.substring(className.indexOf("com")); String signature = jp.getSignature().toString();//获取目标方法签名 System.out.println("signature:" + signature); } }
4.在方法上添加自己自定义的注解
@LogAnnotation(desc = "通过ID获取实体信息") @Override public AdminLog getAdminLogById(Integer id) { return adminLogMapper.getAdminLogById(id); }
MyBatis工作原理