Spring 笔记
PS C:\Users\sw> ls env:classpath Name Value ---- ----- CLASSPATH .;C:\Dev\Java\jdk1.8.0_171/lib/dt.jar;C:\Dev\Java\jdk1.8.0_171/lib/tools.jar
dt.jar 根据 Sun公司定义,把swing用来供给IDE描述 BeanInfo => 由此引入 Spring 一个极为关键的东西 java.beans.PropertyEditor
================================= Ioc 容器 和 依赖注入 =========================
Dependency Injection 是后来 matiin flower 给 IoC 起的一个名字。DI是一种具体实现方式。
Ioc容器的作用举例说明,假设有一个 Sevice 层的类要调用 DAO 层的类 == 该 Service 层的类 依赖了 DAO 层的类,
此时IoC容器通过【xml配置】或者【注解】方式 配置这种依赖关系。
依赖注入的方式有两种 构造注入 和 setter注入。
============================= Bean 装配 ===================================================
作用域 Scope :Singleton Prototype(每次都创建新的实例) Request Session 基于portlet的Session
生命周期 LifeCycle:实现 InitializeBean DisposableBean ,比 xml 早一点。(afterPropertyiesSet start destroy stop )
Aware后缀的接口获取相应的资源:【ApplicationContext】Aware 【BeanNameContext】Aware
自动装配 AutoWiring :配置项 defautl-autowried="byType | byName | constructor"
ResourceLoader:【默认:跟随 context 路径资源】【classpath:资源】【file:资源】【url:资源】
public class GetResource implements ApplicationContextAware{ private ApplicationContext actx; public void setApplicationContext(ApplicationContext actx){ this.actx = actx; } public static void main(Stirng[] args){ actx.getResource("classpath:readme.txt"); //... } }
======================== 使用注解方式装配 bean ======================================
<context:annotation-config / > 查找同一个 ApplicationContext 中的 bean 注解。
<context:component-scan /> 包含 <context:annotation-config / > ,可以扫 @Component @Repository @Service @Controller
xml配置可以改变自动扫描行为
<context:component-scan base-package="org.example"> <!-- 扫 Stub --> <context:include-filter type="regex" expression=".*Stub.*Repository" /> <!-- 忽略@Repository --> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repostory" /> </context:component-scan>
注解方式定义Bean (Id、Scope、
BeanNameGenerator | ScopeMetadataResolver | ...
@Scope("prototype")
@Service("myService") public class MyServiceImpl implements MyService{ }
【@Autowired注解】本身是BeanPostProcessor处理,所以不能在自定义的BeanPostProcessor或自定义的BeanFactoryPostProcessor使用。
因为 @Autowired(required=true) 用在构造器上只允许一个。可以通过 @Required 达到同样的效果。
可以通过 @Autowried 获取 ApplicationContext 资源(Environment、ResourceLoader),而不需要实现 ApplicationContextAware。
获取多个 Bean
可以通过@Autowired 获取所有相同类型的实例 装配到 List 或别的集合,@Order(value="1")可以为集合元素指定顺序。
可以通过@Qualifier 限定缩小范围,获取多个Bean中指定的 Bean。
=================== @Configuration Java Config ====================
@Bean 指定创建对象名字、initMethod、destroyMethod
@ImportResource @Value == <context:property-placeholder location=...>
=========================== AOP 预编译 运行期动态代理 ===========================
程序功能统一维护:日志记录、性能统计、安全控制、事务处理、异常处理
预编译 :AspectJ 完整的AOP
运行期动态代理 (JDK动态代理,CGLib动态代理): Spring AOP、JBoss AOP
pointcut + advice
<aop:config> <aop:aspect id="aspectName" ref="beanName"> <aop:pointcut id="pointcutName" expression="" /> <aop:before method="before" pointcut-ref="pointCutName" /> <aop:after-returning method="afterReturning" pointcut-ref="pointCutName"/> <aop:after-throwing method="afterThrowing" pointcut-ref="pointCutName" /> <aop:after method="afterFinally" pointcut-ref="pointCutName" /> </aop:aspect> </aop:config>
=============================== 面向 AOP 编程 ===================
Soc Seperate on Concern 关注点分离,比如业务和非业务分离开。
权限控制 缓存控制 事务控制 审计日志 性能监控 分布式追踪 异常处理。
硬编码 == 代码侵入性。怎么办?用@Aspect = @Pointcut + Advice(@Before @Atfer(finally) @AfterReturn @AfterThrowing @Around(所有))
切点表达式
① execution【 方法】、@target @args @ within @annoation 【注解】 、within 【包或类型】、this() bean() target() 【对象】、args() 【参数】
② * 任意数量字符 、+ 指定的类及子类、 .. 指定子包或参数
within【包或类型】常用于 限定一下类型 限定一下包
//匹配类型下所有方法 @Pointcut("within(com.example.Sample)")
//匹配包下所有类的方法 @Pointcut("within(com.example.*)")
this() bean() target() 【对象】
@Pointcut("this("com.example.Demo")")//实现IDAO接口对象方法 @Pointcut("target(com.example.IDAO)")@Pointcut("bean(*Service)")
args() 【参数】
@Pointcut("execution(* *..find*(Long))")@Pointcut("args(Long)")
@target @args @ within @annoation 【注解】
@Pointcut("@annoation("com.example.AdminOnly")") //RetentionPolicy要为CLASS @Pointcut("@within("com.example.AdminOnly")") //RetentionPolicy要为RUNTIME @Pointcut("@target("com.example.AdminOnly")") //传参的地方 有@AdminOnly注解 @Pointcut("@args("com.example.AdminOnly")")
execution【 方法】{ * 任意数量字符 、+ 指定的类及子类、 .. 指定子包或参数}
execution{
modifier-pattern ?可省
returnType-pattern
declaringType-pattern?可省
name(param)
throws ?可省
}
@Pointcut("execution(public * com.example.*Service.*(..))") //加两个.. 匹配到子包 @Pointcut("execution(public * com.example..*Service.*(..))")
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 通知 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// @Around = @Before + @After* // 需要把 接入点再传出去 @Around("切点方法名") public Object do(ProceedingJoinPoint joinPoint){ // before Object result = null try{ result = joinPoint.proceeding(joinPoint.getArgs()); // afterReturning }catch (Throwable t) { // afterThrow } finally{ //after(finally) } }
获取参数
@Before("切点方法名&&args(参数名)")
@After*("切点方法名&&args(参数名)")
================================================= AOP 原理就是 =====================================
【静态接口代理模式】。Proxy 负责在具体方法连接点(before、after*),Target仍然负责具体方法逻辑。
【jdk动态接口代理】底层原理使用反射生成 接口实现方法,优点 直接代理掉 一个类的所有方法(现有、未来新增的)
public class JdkProxy implements InvocationHandler{ private Subject subject; public JdkProxy(Subject subject) { this.subject = subject; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before print"); Object result = null; try { result = method.invoke(subject, args); System.out.println("afterReturn print"); } catch (Exception e) { System.out.println("afterThrow print"); throw e; }finally { System.out.println("after print"); } return result; } } public class Client { public static void main(String[] args) { Subject subject = (Subject) java.lang.reflect.Proxy.newProxyInstance(Client.class.getClassLoader(), new Class[] {Subject.class}, new JdkProxy(new SubjectImpl())); subject.request(); } }
【cgLib 继承代理】
static class CGLibMIntercepter implements MethodIntercepter{
@Override
public Object intercept(Object obj,Method method,Object[] args,MethodProxy proxy)throw Throwable{
//关键方法
Object result = proxy.invokeSuper(obj,args);
}
}
public static void main(String[] args){
Subject subject = getProxy(Subject.class,new CGLibMIntercepter());
subject.request();
}
public static Object getProxy(Class clz,MethodIntercepter intercepter){ Enhancer enhancer = new Enhancer(); enhancer.setSuperClass(clz); enhancer.setCallback(intercepter); return enhancer.create(); }
JDK与Cglib代理对比:
1:JDK只能针对有接口的类的接口方法进行动态代理;
2:Cglib基于继承来实现代理,无法对static、final类进行代理;
3:Cglib基于继承来实现代理,无法对private、static方法进行代理。
Spring 对于两种实现方式都支持配置!DefaultAopProxyFactory 比如接口用JDK动态代理,是继承用CgLib代理。(PS:Spring源码好复杂。。。还是掌握简单的理解概念就好。)
【配置】@EnableAspectJAutoProxy(proxyTargetClass = true) 强制使用 CgLib 代理。
AOP 怎么链式调用起来?使用了责任链模式。
============================= 事务管理 ====================================
AtomicityConsistencyIsolationDuralbility == ACID == 原子性(最小不可分割操作单位)、一致性(前后状态)、隔离性(并发事务之间)、持久性(写入记录)
经典例子 转账。【事务回滚】
【PlatformTransactionManager 事务管理器】Platform 指的是 iBatis Hibernate JPA 具体实现。
【TransactionDefinition 事务定义信息(隔离 传播 超时 只读)】
【DEFAULT】mysql _ REPEATABLE_READ
【READ_UNCOMMITED】不隔离问题 脏读、不可重复读、幻读
【READ_COMMITED】【脏读】一个事务读取另一个事务改写还没提交的数据,没提交如果回滚,读到的数据是无效的。
【REPEATABLE_READ】【不可重复读】一个事务下,多次读取数据,得到不同结果,
【SERIALIZABLE】【幻读】一个事务在执行读取的时候,被插入另一个事务记录。
传播
【目的 支持当前事务】
【传播当前事务,没有要传播的事务】支持传并创建、支持传但不创建、不传就抛异常 PROPAGATION_ ( REQUIRED、SUPPORTS、MANDATORY )
【让事务分开】
【传播当前事务,有要传播的事务】另外创建、挂起当前但不支持传、拒绝且抛异常】PROPAGATION_ ( REQUIRED_NEW、NOT_SUPPORTED、NEVER )
【让事务嵌套执行 利用保存点回滚】
PROPAGATION_NESTED
【TransactionStatus 】
是否有保存点 等状态
--------------------------------------------------------------------------- PlatformTransactionManager、CombopooledDataSource 事务的使用 ===========================
编程式使用事务 TransactionTemplate
声明式使用事务 AOP
1种 TransactionProxyBean
<bean id="accountServiceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <!-- 配置目标对象 --> <property name="target" ref="accountService"/> <!-- 注入事务管理器 --> <property name="transactionManager" ref="transactionManager"/> <!-- 注入事务属性 --> <property name="transactionAttributes"> <props> <!-- PROPAGATION_REQUIRED:支持当前事务,如果不存在就新建一个事务 --> <!-- prop的格式: * PROPAGATION 事务的传播行为 * ISOLATION 事务的隔离级别 * readOnly 只读(不可进行修改) * -Exception 发生哪些异常回滚事务 * +Exception 发生哪些异常事务不回滚 --> <prop key="具体方法或通配符">PROPAGATION_REQUIRED</prop> </props> </property>
</bean>
2种 AspectJ 只要调用到 AccountService的所有方法,都会启动通知。
<!-- 配置事务的通知 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="transfer" propagation="REQUIRED"/> </tx:attributes> </tx:advice> <!-- 配置切面 --> <aop:config> <!-- 配置切入点 --> <aop:pointcut expression="execution(* com.demo3.AccountService.*(..))" id="pointcut1"/> <!-- 配置切面 --> <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/> </aop:config>
3种 @Transactional
<!-- 开启注解事务 --> <tx:annotation-driven transaction-manager="transactionManager"/> 在对应需要事务管理的业务层上加上注解 @Transactional