Spring框架
一、什么是Spring框架?
Spring框架是一个轻量级的IOC和AOP的容器框架,能够为企业级开发提供一站式服务。
- 轻量级:大小只有2M,上手比较容易。
- IOC:Spring框架的核心之一,称为控制反转,也叫依赖注入。
- AOP:Spring框架的核心之一,称为面向切面编程。
- 容器:可以创建对象,配置对象,并管理对象的整个生命周期。
二、IOC
(1)概念
IOC叫控制反转,是一种编程思想,简单的来说,就是原来创建对象和管理对象由程序员来完成,现在将创建对象和管理对象交给容器来完成。
(2)作用
IOC的主要作用就是为程序解耦,在创建对象是,通常来说是需要new一个对象,通过IOC,我们就可以不用写new了,通过特殊的标注就可以去掉new,这样也就有效的降低了程序的耦合度。这样就可以让开发者只关注自己的业务逻辑,更好的去进行扩展和维护。
三、IOC容器
在Spring中,IOC容器主要分为两种,BeanFactory和ApplicationContext。
(1)BeanFactory
BeanFactory是IOC容器的顶级接口,是IOC容器的最基础实现,也是访问Spring容器的根接口,负责对bean的创建,访问等工作。
(2)ApplicationContext
ApplicationContext是Spring中的核心接口和容器,允许容器通过应用程序上下文环境创建、获取、管理bean。
该接口具有三个常用的实现类:
- 1、ClassPathXmlApplicationContext:可以加载类路径下的配置文件,要求配置文件必须在类路径之下。
- 2、FileSystemXmlApplicationContext:可以加载磁盘中任意路径下的配置文件,要求具有访问权限。
- 3、AnnotationConfigApplicationContext:用于读取注解创建容器。
四、Spring中的重要注解
(1)@Component 组件,被标记的类会被Spring扫描到,交给Spring容器进行管理。
(2)@ComponentScan 组件扫描,标记在配置类上,用于扫描某一个包下带@Component的类。
(3)@Configuration 配置类,标记在类上,该类作为配置类代替XML。
(4)@Value 注入值类型数据,配置属性或set方法上。
(5)@Autowrie 自动装配,默认按类型进行注入。
(6)@Qualifier 标记名称,配置在类和注入属性上,用于区分类型相同的对象。
(7)@Resource 自动装配,类似Autowired,默认按名称注入,名称没有再按类型注入。
(8)@Repository 类似@Component,标记DAO实现类。
(9)@Service 类似@Component,标记Service实现类。
(10)@Controller 类似@Component,标记Controller类。
五、AOP
(1)概念
AOP叫面向切面编程,是OOP的一种重要补充,也是Spring的另一个核心。AOP关注横向关系,能够为多个相互没有关系,又都需要某些共同功能的类,提供一些通用服务(如:日志、权限、缓存、事务等)。
(2)作用
可以为代码解耦,将与类的核心业务无关,又都需要的功能封装起来,让类只关注自己的核心业务,分离了系统的核心业务和非核心业务。
(3)AOP中的核心术语
- 1、切面(Aspect)
对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为切面。- 2、连接点(joinpoint)
被拦截到的点,因为Spring只支持方法类型的连接点,所以在Spring中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器。- 3、切入点(pointcut)
对连接点进行拦截的定义。- 4、通知(advice)
所谓通知指的就是指拦截到连接点之后要执行的代码,通知分为前置、后置、异常、最终、环绕通知五类。- 5、目标对象(target)
代理的目标对象,将切面应用到目标对象并导致代理对象创建的过程。- 6、引入(introduction)
在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段。
(4)引入依赖
在使用前,需要引入以下依赖:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.5</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
(5)在AOP的XML配置文件中,我们需要引入以下标签
<!--配置包扫描-->
<context:component-scan base-package="项目所在包"></context:component-scan>
<!--配置提供服务的对象-->
<bean id="pliceService" class="服务的对象所在的包"></bean>
<!--AOP的配置-->
<aop:config>
<!--配置切入点 *代表任意长度字符 ..代表任意文件或者文件夹-->
<aop:pointcut id="pointcut" expression="execution(* com..*.walk(..)) || execution(* com..*.study(..))" />
<!--配置切面 ref配置服务的对象,也就是bean中的id-->
<aop:aspect id="policeaspect" ref="pliceService">
<!--配置前置服务-->
<aop:before method="watch" pointcut-ref="pointcut"></aop:before>
<!--配置后置服务-->
<aop:after method="after" pointcut-ref="pointcut"></aop:after>
<!--环绕通知-->
<aop:around method="around" pointcut-ref="pointcut"></aop:around>
<!--异常通知-->
<aop:after-throwing method="afterThrow" pointcut-ref="pointcut" throwing="throwable"></aop:after-throwing>
<!--返回通知-->
<aop:after-returning method="afterReturn" pointcut-ref="pointcut"></aop:after-returning>
</aop:aspect>
</aop:config>
(6)AOP的注解配置
- 1、@Aspect 切面,配置到切面类上
- 2、@PointCut(“表达式”) 配置切入点,加在方法上
- 3、@Before 配置前置通知方法
- 4、@After 配置后置通知方法
- 5、@Around 配置环绕通知方法
- 6、@AfterReturning 配置后置返回值通知方法
- 7、@AfterThrowing 配置后置抛出异常通知方法
六、编写日志跟踪
可以实时跟踪程序编写运行中遇到的bug以及所有的方法及参数。
(1)导如log4j的依赖
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
(2)编写log4j.properties配置文件
# ROOTER
log4j.rootLogger=DEBUG,CONSOLE,FILE
# CONSOLE
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%-d{yyyy-MM-dd HH\:mm\:ss} %-5p %-20c %x %t %m%n
# FILE
log4j.appender.FILE=org.apache.log4j.RollingFileAppender
log4j.appender.FILE.File=logs.log
log4j.appender.FILE.MaxBackupIndex=20
log4j.appender.FILE.MaxFileSize=10MB
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.ConversionPattern=%-d{yyyy-MM-dd HH\:mm\:ss} %-5p %-20c %x %m%n
# ERROR
log4j.appender.ERR = org.apache.log4j.DailyRollingFileAppender
log4j.appender.ERR.File =error.log
log4j.appender.ERR.Append = true
log4j.appender.ERR.Threshold = ERROR
log4j.appender.file.DatePattern='.'yyyy-MM-dd'.log'
log4j.appender.ERR.layout = org.apache.log4j.PatternLayout
log4j.appender.ERR.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
(3)编写日志类
import org.apache.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class Log_Config {
//创建日志对象
private Logger logger = Logger.getLogger(Log_Config.class);
@Pointcut("execution(* com.eshop..impl.*Impl.*(..)) || execution(* com.eshop..*Servlet.*(..))")
public void logPointcut(){
}
//配置环绕通知
@Around("logPointcut()")
public Object aroundLog(ProceedingJoinPoint joinPoint) throws Throwable{
//记录方法执行前时间
long start = System.currentTimeMillis();
//获取方法名
if (logger.isDebugEnabled()) {
logger.debug(joinPoint.getSignature().getName());
}
//获取参数
Object[] args = joinPoint.getArgs();
for (Object arg : args) {
if (logger.isDebugEnabled()){
logger.debug("参数:"+arg);
}
}
//获取返回值
Object proceed = joinPoint.proceed();
if (logger.isDebugEnabled()){
logger.debug("方法返回值:"+proceed);
}
//获取执行时间
long end = System.currentTimeMillis();
if (logger.isDebugEnabled()){
logger.debug("方法执行时间:"+(end - start));
}
return proceed;
}
}