Spring的反向控制IOC
什么是IOC?
1)控制反转,把对象创建和对象之间的调用过程,交给 Spring 进行管理 (2)使用 IOC 目的:为了耦合度降低
IOC(BeanFactory)
IOC思想基于IOC容器,IOC容器的底层就是对象工厂,存放了多个map(key,value)。
BeanFactory是生产bean的工厂,负责生产和管理各个Bean实例,也是Spring容器的基本实现,一般不提供开发人员使用。
ApplicationContext:是BeanFactory的子接口,一般由开发人员使用。
声明为Bean的注解?
@Component :通用的注解,可标注任意类为 Spring 组件。如果一个 Bean 不知道属于哪个层,可以使用@Component 注解标注。
@Repository : 对应持久层即 Dao 层,主要用于数据库相关操作。
@Service : 对应服务层,主要涉及一些复杂的逻辑,需要用到 Dao 层。
@Controller : 对应 Spring MVC 控制层,主要用于接受用户请求并调用 Service 层返回数据给前端页面。
其他注解
@bean相比于@Component的自定义性更强,例如将第三类库装配到Spring容器中,只能使用@Bean。
@ComponeScan 开启注解扫描
@Autowired 优先根据类型去匹配并注入Bean
@Resource 可以根据类型注入,也可以根据名称注入
例如:
@Resouces(name = "userDapImpl") //根据名称注入
private UserDao userDao;
Spring中Bean的作用域?
singleton : IoC 容器中只有唯一的 bean 实例。Spring 中的 bean 默认都是单例的,是对单例设计模式的应用。
prototype : 每次获取都会创建一个新的 bean 实例。也就是说,连续 getBean() 两次,得到的是不同的 Bean 实例,即多实例。
request (仅 Web 应用可用): 每一次 HTTP 请求都会产生一个新的 bean(请求 bean),该 bean 仅在当前 HTTP request 内有效。session (仅 Web 应用可用) : 每一次来自新 session 的 HTTP 请求都会产生一个新的 bean(会话 bean),该 bean 仅在当前 HTTP session 内有效。
application/global-session (仅 Web 应用可用): 每个 Web 应用在启动时创建一个 Bean(应用 Bean),该 bean 仅在当前应用启动时间内有效。
websocket (仅 Web 应用可用):每一次 WebSocket 会话产生一个新的 bean
Bean的生命周期?
(1)实例化一个Bean,也就是采用new一个对象
(2)IOC依赖注入,按照Spring上下文对实例化的Bean进行配置。
(3)SetBeanName实现 如果这个Bean已经实现了BeanNameAware接口,则会调用它实现setBeanName
(4)BeanFactoryAware实现,如果这个Bean 已经实现了BeanFactoryAware 接口,会调用它实现的setBeanFactory,
setBeanFactory(BeanFactory)传递的是Spring 工厂自身(可以用这个方式来获取其它Bean,
(5)ApllicationContextAware实现,如果这个Bean 已经实现了ApplicationContextAware 接口,会调用
setApplicationContext(ApplicationContext)方法,传入Spring 上下文
(6)postProcessBeforeInitialization 接口实现-初始化预处理 如果这个Bean 关联了BeanPostProcessor 接口,将会调用
postProcessBeforeInitialization(Object obj, String s)方法
(7) Init-Method 如果Bean 在Spring 配置文件中配置了init-method 属性会自动调用其配置的初始化方法。
(8)postProcessAfterInitialization如果这个Bean 关联了BeanPostProcessor 接口,将会调用 post Process After Initialization(Object obj, String s)方法。
(9)Destroy过期自动清理 当Bean 不再需要时,会经过清理阶段,如果Bean 实现了DisposableBean 这个接口,会调
用那个其实现的destroy()方法;
(10)destroy-method 自配置清理
最后,如果这个Bean 的Spring 配置中配置了destroy-method 属性,会自动调用其配置的销毁方法。
Spring的面向切面编程
目的:对业务逻辑的各个部分进行隔离、降低耦合度、提高代码的重用性,主要是将哪些与业务无关,但是需要使用的逻辑封装起来(例如事物处理、日志管理等)
Aop的主要应用场景
- Authentication 权限
- Caching 缓存
- Context passing 内容传递
- Error handling 错误处理
- Lazy loading 懒加载
- Debugging 调试
- logging, tracing, profiling and monitoring 记录跟踪 优化 校准
- Performance optimization 性能优化
- Persistence 持久化
- Resource pooling 资源池
- Synchronization 同步
- Transactions 事务
AOP的术语
Aop的底层原理
Spring 提供了两种方式来生成代理对象: JDKProxy 和Cglib,具体使用哪种方式生成由AopProxyFactory根据AdvisedSupport 对象的配置来决定。默认的策略是如果目标类是接口,
则使用JDK 动态代理技术,否则使用Cglib 来生成代理。
1.利用JDK动态代理
利用Proxy类创建代理对象(java.lang.reflect.proxy),利用newProxyInstance创建对象实例。
参数分别为:类加载器、增强方法所在类实现的接口,实现接口的InvocationHandler(主要用于写实现部分)
2.使用GLIC实现动态代理
CGLib 全称为Code Generation Library,是一个强大的高性能,高质量的代码生成类库,可以在运行期扩展Java 类与实现Java 接口,CGLib 封装了asm,可以再运行期动态生成新的class。和JDK 动态代理相比较:JDK 创建代理有一个限制,就是只能为接口创建代理实例,而对于没有通过接口定义业务方法的类,则可以通过CGLib 创建动态代理。
@Aspect
public class TransactionDemo {
@Pointcut(value="execution(* com.yangxin.core.service.*.*.*(..))")
public void point(){
}
@Before(value="point()")
public void before(){
System.out.println("transaction begin");
}
@AfterReturning(value = "point()")
public void after(){
System.out.println("transaction commit");
}
@Around("point()")
public void around(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("transaction begin");
joinPoint.proceed();
System.out.println("transaction commit");
}
}
Aop的实际操作
Spring AOP 属于运行时增强,而 AspectJ 是编译时增强。 Spring AOP 基于代理(Proxying),而 AspectJ 基于字节码操作(Bytecode Manipulation)。
一般将AspectJ和Spring一起使用来进行AOP操作,1)通过xml配置文件 2)基于注解实现
切入点表达式 execution ([权限修饰符] [返回类型] [类全路径][方法名称][参数列表])
例子:execution * com.atowner.dao.BookDao,add(…) 对add方法进行增强
在增强的类上标注@Aspect,在作为通知方法上加入通知类型的注解,使用切入点表达式配置,若有多个增强类对同一个方法增强,设置增强类的优先级@Order(1).
通知类型:
Before(前置通知):目标对象的方法调用之前触发
After (后置通知):目标对象的方法调用之后触发
AfterReturning(返回通知):目标对象的方法调用完成,在返回结果值之后触发
AfterThrowing(异常通知) :目标对象的方法运行中抛出 / 触发异常后触发。
AfterReturning 和 AfterThrowing 两者互斥。如果方法调用成功无异常,则会有返回值;如果方法抛出了异常,则不会有返回值。
Around (环绕通知):编程式控制目标对象的方法调用。环绕通知是所有通知类型中可操作范围最大的一种,因为它可以直接拿到目标对象,以及要执行的方法,所以环绕通知可以任意的在目标对象的方法调用前后搞事,甚至不调用目标对象的方法