一、简介
Spring Framework(简称Spring)是J2EE应用程序框架,它是针对Bean的生命周期进行管理的轻量级容器(Lightweight container)。Spring是一个开源的控制反转和面向切面的容器框架,主要目的是简化企业开发。Spring配置文件为applicationContext.xml。
二、控制反转(IOC)
所谓控制反转就是应用本身不负责依赖对象的创建及维护,依赖对象的创建及维护是由外部容器负责的。这样控制权就由应用转移到了外部容器,控制权的转移就是所谓反转。其主要实现为
依赖查找(Dependency Lookup):容器提供回调接口和上下文环境给组件。EJB和Apache Avalon都使用这种方式。
依赖注入(Dependency Injection):组件不做定位查询,只提供普通的Java方法让容器去决定依赖关系。
目前主要使用依赖注入。DI和IOC是差不多的概念。IOC侧重于原理,DI侧重于实现。
DI三种方式:
1、setter注入
<!-- 注册userService -->
<bean id="userService" class="com.lyu.spring.service.impl.UserService">
<!-- 写法一 -->
<!-- <property name="UserDao" ref="userDaoMyBatis"></property> -->
<!-- 写法二 -->
<property name="userDao" ref="userDaoMyBatis"></property>
</bean>
<!-- 注册mybatis实现的dao -->
<bean id="userDaoMyBatis" class="com.lyu.spring.dao.impl.UserDaoMyBatis"></bean>
public class UserService implements IUserService {
private IUserDao userDao1;
public void setUserDao(IUserDao userDao1) {
this.userDao1 = userDao1;
}
public void loginUser() {
userDao1.loginUser();
}
}
2、构造器注入
<!-- 注册userService -->
<bean id="userService" class="com.lyu.spring.service.impl.UserService">
<constructor-arg ref="userDaoJdbc"></constructor-arg>
</bean>
<!-- 注册jdbc实现的dao -->
<bean id="userDaoJdbc" class="com.lyu.spring.dao.impl.UserDaoJdbc"></bean>
public class UserService implements IUserService {
private IUserDao userDao;
public UserService(IUserDao userDao) {
this.userDao = userDao;
}
public void loginUser() {
userDao.loginUser();
}
}
3、基于注解注入(使用较多)
主要有四种注解可以注册bean,每种注解可以任意使用,只是语义上有所差异:
- @Component:可以用于注册所有bean
- @Repository:主要用于注册dao层的bean
- @Controller:主要用于注册控制层的bean
- @Service:主要用于注册服务层的bean
描述依赖关系主要有两种:
- @Resource:java的注解,默认以byName的方式去匹配与属性名相同的bean的id,如果没有找到就会以byType的方式查找,如果byType查找到多个的话,使用@Qualifier注解(spring注解)指定某个具体名称的bean。
@Resource
@Qualifier("userDaoMyBatis")
private IUserDao userDao;
public UserService(){
}
- @Autowired:spring注解,默认也是以byName的方式去匹配与属性名相同的bean的id,如果没有找到,就通过byType的方式去查找,如果查找到多个,用@Qualifier注解限定具体使用哪个。
@Autowired
@Qualifier("userDaoJdbc")
private IUserDao userDao;
三、面向切面(AOP)
AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。
使用场景:
- Authentication 权限
- Caching 缓存
- Context passing 内容传递
- Error handling 错误处理
- Lazy loading 懒加载
- Debugging 调试
- logging, tracing, profiling and monitoring 记录跟踪 优化 校准
- Performance optimization 性能优化
- Persistence 持久化
- Resource pooling 资源池
- Synchronization 同步
- Transactions 事务
相关概念:
- 方面(Aspect):一个关注点的模块化,这个关注点实现可能另外横切多个对象。事务管理是J2EE应用中一个很好的横切关注点例子。方面用Spring的 Advisor或拦截器实现。
- 连接点(Joinpoint): 程序执行过程中明确的点,如方法的调用或特定的异常被抛出。
- 通知(Advice): 在特定的连接点,AOP框架执行的动作。Spring中定义了五个advice: 前置通知(Before),后置通知(After), 返回通知(After-returning),异常通知(After-throwing)和环绕通知(Around)
- 切入点(Pointcut): 指定一个通知将被引发的一系列连接点的集合。AOP框架必须允许开发者指定切入点:例如,使用正则表达式。 Spring定义了Pointcut接口,用来组合MethodMatcher和ClassFilter,可以通过名字很清楚的理解, MethodMatcher是用来检查目标类的方法是否可以被应用此通知,而ClassFilter是用来检查Pointcut是否应该应用到目标类上
- 引入(Introduction): 添加方法或字段到被通知的类。 Spring允许引入新的接口到任何被通知的对象。例如,你可以使用一个引入使任何对象实现 IsModified接口,来简化缓存。Spring中要使用Introduction, 可有通过DelegatingIntroductionInterceptor来实现通知,通过DefaultIntroductionAdvisor来配置Advice和代理类要实现的接口
- 目标对象(Target Object): 包含连接点的对象。也被称作被通知或被代理对象。POJO
- AOP代理(AOP Proxy): AOP框架创建的对象,包含通知。 在Spring中,AOP代理可以是JDK动态代理或者CGLIB代理。
- 织入(Weaving): 组装方面来创建一个被通知对象。这可以在编译时完成(例如使用AspectJ编译器),也可以在运行时完成。Spring和其他纯Java AOP框架一样,在运行时完成织入。
1、实现(基于注解)
LogAspect中的代码
/**
* 1、告诉ioc这个组件的存在
* 2、告诉ioc这是一个切面使用@Aspect
* @author syl
*
*/
@Aspect
@Component
public class LogAspect {
/**
* try{
* @Before前置通知
* method.invoke();
* @AfterRunning返回通知
* }catch(e){
* @AfterThrowing:异常通知,
* }
* @After
*
* 告诉Spring这些放在都在那个方法的哪个位置执行
* 1)、告诉位置
[1]@Before:前置通知,在方法执行之前执行
[2]@After:后置通知,在方法执行最终结束之后执行。
如果没异常
[3]@AfterRunning:返回通知,在方法返回结果之后执行
[4]@AfterThrowing:异常通知,在方法抛出异常之后执行
1、编写切入点表达式,来告诉spring是切入哪个方法的这个位置
*/
@Before(value="execution(public * *.add(int, int))")
public void logStart(){
System.out.println("AOP日志,方法开始");
}
@After(value="execution(public * *.add(int, int))")
public void logEnd(){
System.out.println("AOP日志,方法最终结束");
}
@AfterThrowing(value="execution(public * *.add(int, int))")
public void logException(){
System.out.println("AOP日志,方法出现异常");
}
@AfterReturning(value="execution(public * *.add(int, int))")
public void logReturn(){
System.out.println("AOP日志,方法正常执行");
}
applicationContext中的内容
<!--1、自动扫描所有的组件 -->
<context:component-scan base-package="com.atguigu"></context:component-scan>
<!--2、开启基于注解的aop功能 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<!--
0)、被代理对象也得先加入到ioc中
1)、编写日志切面,并加入到ioc中,@Component @Aspect
2)、给切面编写通知方法。
3)、加上何时何地切入的注解。切入点表达式
4)、开启基于注解的aop功能即可
-->