IOC:Inversion of Control (控制反转)。
描述的事情:Java开发领域对象的创建和管理问题。
传统的开发方式:在类A依赖类B的时候,往往会在类A中new一个B对象。
public class A{ B b = new B(); b.hello();}
IOC思想下的开发方式:不用自己去new对象,而是由IOC容器去实例化对象并进行管理。我们需要用到哪个对象,去IOC容器中拿取。
此时,创建和管理对象的权力(控制),交给了外部环境(反转)。
// IOC容器Map
对象之间的耦合问题。
传统的开发方式:
// 定义操作数据库的接口类public interface AccountDao {}// 利用传统JDBC实现操作数据库的接口public class JdbcAccountDaoImpl implements AccountDao {}// 业务逻辑层public class TransferServiceImpl implements TransferService { // 此时操作数据库的方式为 传统的JDBC private AccountDao accountDao = new JdbcAccountDaoImpl();}// 若此时抛弃传统JDBC实现操作数据库 改用Mybatis实现操作数据库public class MybatisAccountDaoImpl implements AccountDao {}// 需要将业务逻辑层代码改为public class TransferServiceImpl implements TransferService { // 此时操作数据库的方式为 Mybatis private AccountDao accountDao = new MybatisAccountDaoImpl();}// 若业务层代码中有“成千上万”个地方需要更换new的对象,此时的工作量会巨大。不符合Java面向接口编程的习惯。
IOC思想下的开发方式:
// 业务逻辑层public class TransferServiceImpl implements TransferService { // 此时只定义需要用到的接口 不去new实现 private AccountDao accountDao;}
3.IOC和DI的区别DI:Dependancy Injection(依赖注入)。
IOC和DI描述都是对象实例化及依赖关系维护这件事,只是站在的角度不同。IOC是站在对象的角度,将对象实例化和管理的权限交给了容器。DI是站在容器的角度,容器会把对象依赖的其他对象注入。
基本使用 纯XML模式pom.xml
resourcesapplicationContext.xml
public class CreateBeanFactory { // 在静态方法中实例化对象 将自己 new 的对象要放到容器中 public static ConnectionUtils getInstanceStatic() { return new ConnectionUtils(); } // 实例化方法 public ConnectionUtils getInstance() { return new ConnectionUtils(); }}
启动JavaEE方式
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
JavaSE方式
resourcesapplicationContext.xml
@Controller:用于控制层
@Service:用于服务层
@Repository:用于Dao层scope属性@Scope(“prototype”),默认单例,注解加在类上init-method属性@PostConstruct,注解加在⽅法上,该⽅法就是初始化后调⽤的⽅法destroy-method属性@PreDestory,注解加在⽅法上,该⽅法就是销毁前调⽤的⽅法DI依赖注入的方式@Autowired
org.springframework.beans.factory.annotation.Autowired
默认按照类型注入。如果一个类型的实现方式有很多需要配合@Qualififier去告诉Spring配置哪个对象。纯注解模式
@Configuration@ComponentScan({"com.demo"})public class SpringConfig {}
启动JavaEE方式
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
JavaSE方式
@Component@PropertySource({"classpath:jdbc.properties"})public class DataSourceConfig { @Value("${jdbc.driver}") private String driverClassName; @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String username; @Value("${jdbc.password}") private String password; // 自己 new 一个对象 放入 IOC 容器 @Bean public DruidDataSource createDataSource() { DruidDataSource druidDataSource = new DruidDataSource(); druidDataSource.setDriverClassName(driverClassName); druidDataSource.setUrl(url); druidDataSource.setUsername(username); druidDataSource.setPassword(password); return druidDataSource; } @Bean public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { return new PropertySourcesPlaceholderConfigurer(); }}
高级特性 lazy-init 延迟加载概念:ApplicationContext 容器的默认行为是在启动服务的时候将所有 singleton 类型的 bean 提前进行实例化。将 lazy-init 设置为 true,bean 将不会再 ApplicationContext 启动时提前被实例化,而是第一次向容器通过 getBean 索取 bean 时实例化。此属性对 scope=“pototype” 的 bean 不生效。
特殊情况:存在两个bean。bean2 设置 lazy-init = true;bean1 设置 lazy-init = false,此时 bean2 会延迟加载。但是若 bean2 被 bean1 引用,在实例化 bean1 的同时,bean2也会被实例化。
FactoryBean概念:Spring 有两种bean:一种普通的 bean,一种工厂 bean。我们可以借助 FactoryBean 接口生成某一类型的 bean 实例。
// 利用 ResultBean 创建 Result 类型的 beanpublic class ResultBean implements FactoryBean
1)创建 beanFactory。可以实现 BeanFactoryPostProcessor 接口拿到 beanFactory。
@Componentpublic class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { System.out.println("MyBeanFactoryPostProcessor:" + beanFactory); }}
2)初始化BeanPostProcessor。
@Componentpublic class MyBeanPostprocessor implements BeanPostProcessor { public MyBeanPostprocessor() { System.out.println("2)初始化MyBeanPostprocessor"); }}
3)bean的构造方法。
public class LifeCycle implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean { public LifeCycle() { System.out.println("3)LifeCycle的构造方法"); }}
4)BeanNameAware 接口。
@Overridepublic void setBeanName(String name) {System.out.println("4)BeanNameAware:" + name);}
5)BeanFactoryAware 接口。
@Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException { System.out.println("5)BeanFactoryAware:" + beanFactory);}
6)ApplicationContextAware 接口。
@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException { System.out.println("6)ApplicationContextAware:" + applicationContext);}
7)BeanPostProcessor 接口的 postProcessBeforeInitialization 方法。
@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("7)postProcessBeforeInitialization:" + beanName); return bean;}
8)@PostConstruct 注解标注的方法。
@PostConstructpublic void PostConstruct() { System.out.println("8)PostConstruct");}
9)InitializingBean 接口的 afterPropertiesSet 方法。
@Overridepublic void afterPropertiesSet() throws Exception { System.out.println("9)InitializingBean:afterPropertiesSet");}
10)xml 中 init-method 方法。
public void initMethod() { System.out.println("10)initMethod");}
11)BeanPostProcessor 接口的 postProcessAfterInitialization 方法。
@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("11)postProcessAfterInitialization:" + beanName); return bean;}
12)ApplicationContext 的创建。
public void TestLifeCycle() { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); System.out.println("12)TestLifeCycle:" + context); context.close();}
13)@PreDestroy 注解标注的方法。
@PreDestroypublic void PreDestroy() { System.out.println("13)PreDestroy");}
14)DisposableBean 接口的 destroy 方法。
@Overridepublic void destroy() throws Exception { System.out.println("14)DisposableBean:destroy");}
15)xml 中 destroy-method。
public void destroyMethod() { System.out.println("15)destroyMethod");}
AOP的基本应用 概念 1.什么是AOPAOP:Aspect Oriented Programming(面向切面编程)。
OOP:Object Oriented Programming(面向对象编程)。
AOP 是 OOP 的延续。OOP 三大特征:封装,继承,多态。是一种垂直继承体系。
OOP开发方式:
Public class Animal { public void eat(){ System.out.println("eating...");} public void run(){ System.out.println("running...");}} Public class Cat extends Animal { // 此时不需要额外的再书写 eat 和 run 方法 解决了大多数代码重复问题 // 然而如果每个 System.out.println() 前后需要增加大量重复的代码 此时 OOP就不能解决代码重复问题 // 而且将业务代码和 日志或性能监控代码混杂在一起,代码臃肿,维护不方便}
AOP优化方式:
public class ProxyFactory { // JDK 动态代理 public Object getJdkProxy(Object obj) { return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return getObject(method, args, obj); } }); } private Object getObject(Method method, Object[] args, Object obj) throws SQLException, IllegalAccessException, InvocationTargetException { // 此处可以编写横切逻辑代码... Object result = null; try { result = method.invoke(obj, args); // 此处可以编写横切逻辑代码... } catch (Exception e) { // 此处可以编写横切逻辑代码... throw e; } return result; } // cglib 动态代理 public Object getCglibProxy(Object obj) { return Enhancer.create(obj.getClass(), new MethodInterceptor() { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { return getObject(method, objects, obj); } }); }}
2.AOP中的术语默认情况下,Spring 会根据被代理对象是否实现了接口来选择是否使用 JDK动态代理 还是 cglib动态代理。当没有实现接口的时候选择 cglib 动态代理,当实现接口的时候会选择 JDK官方的代理技术,我们也可以通过配置的方式让 Spring 强制使用 cglib。
基本使用 纯XML模式pom.xml
resourcesapplicationContext.xml
xmlns:aop="http://www.springframework.org/schema/aop"http://www.springframework.org/schema/aophttps://www.springframework.org/schema/aop/spring-aop.xsd
XML + 注解模式
@Component@Aspectpublic class LogUtils { @Pointcut("execution(* com.demo.service.impl.TransferServiceImpl.*(..))") public void pt1() { } @Before("pt1()") public void beforeMethod(JoinPoint joinPoint) { Object[] args = joinPoint.getArgs(); // 可以拿到 所有传递进来的参数 for (Object arg : args) { System.out.println(arg); } System.out.println("业务逻辑开始执行之前执行......."); } // finally @After("pt1()") public void afterMethod() { System.out.println("业务逻辑结束时执行,无论异常与否都执行......."); } @AfterThrowing("pt1()") public void exceptionMethod() { System.out.println("异常时执行......."); } @AfterReturning(value = "pt1()",returning = "rtValue") public void successMethod(Object rtValue) { System.out.println(rtValue); System.out.println("业务逻辑正常返回时执行......."); }// @Around("pt1()") public void aroundMethod(ProceedingJoinPoint proceedingJoinPoint) { System.out.println("在执行方法之前"); try { // 控制原有业务逻辑是否执行 proceedingJoinPoint.proceed(); System.out.println("在执行方法之后"); } catch (Throwable throwable) { throwable.printStackTrace(); System.out.println("有异常时执行"); } finally { System.out.println("最终执行"); } }}
纯注解模式@EnableAspectJAutoProxypublic class SpringConfig {}
Spring 声明式事务的支持 事务的四大特性(ACID)事务往往定义在 service 层。如果 service 层方法 A 调用了另一个 service 层方法 B,A 和 B 本身都被添加了事务,那么 A 调用 B 的时候,就需要进行一些协商,这就叫做事务的传播行为。A 调用 B,我们需要站在 B 的角度来定义事务的传播行为。
1)PROPAGATION_REQUIRED:B 如果没有事务,就新建一个事务。如果 A 已经存在一个事务,就加入到A的事务中。这是常见的选则。用于增删改查。
2)PROPAGATION_SUPPORTS:B 支持 A 的事务,如果 B 没有事务,就以非事务方式执行。常用于查询。
基本使用 纯XML模式pom.xml
resources/applicationContext.xml
xmlns:tx="http://www.springframework.org/schema/tx"http://www.springframework.org/schema/txhttps://www.springframework.org/schema/tx/spring-tx.xsd
resources/applicationContext.xml
@Service("transferService")public class TransferServiceImpl implements TransferService {@Override // 配置声明式事务 注解里面有默认值 @Transactional public void transfer() throws Exception { }}
纯注解模式@Configuration@ComponentScan({"com.demo"})@EnableTransactionManagementpublic class SpringConfig {}// 自己 new 一个对象 放入 IOC 容器@Beanpublic DruidDataSource createDataSource() { DruidDataSource druidDataSource = new DruidDataSource(); druidDataSource.setDriverClassName(driverClassName); druidDataSource.setUrl(url); druidDataSource.setUsername(username); druidDataSource.setPassword(password); return druidDataSource;}// JdbcTemplate 放入容器@Beanpublic JdbcTemplate createJdbcTemplate(DruidDataSource druidDataSource) { return new JdbcTemplate(druidDataSource);}// DataSourceTransactionManager 声明式事务放入容器@Beanpublic DataSourceTransactionManager dataSourceTransactionManager(DruidDataSource druidDataSource) { return new DataSourceTransactionManager(druidDataSource);}
参考git:https://gitee.com/zhangyizhou/learning-spring-demo.git
1.自定义 ioc 和 aop 项目:lagou-transfer
1.spring ioc 纯xml项目:lagou-transfer-iocxml
2.spring ioc xml +注解项目;aop 纯xml项目:lagou-transfer-ioc-xml-anno
3.spring ioc+aop 纯注解项目:lagou-transfer-ioc-anno
4.spring 声明周期项目:lagou-spring-life-cycle
5.声明式事务项目:lagou-transfer-transaction