- /**
- * @Author:jimisun
- * @Description:
- * @Date:Created in 07:44 2018-09-27
- * @Modified By:
- */
- public class BeautifulGirl implements Gril {
- private Action action;
- public BeautifulGirl(Action action) {
- this.action = action;
- }
- @Override
- public void action() {
- action.action();
- }
- }
从上面实例代码中可以看到 BeautifulGirl 本身并没有创建任何的动作, 而是通过构造方法传入一个实现了 Action(动作)接口的实现类即可, 也就是说 BeautifulGirl 可以完成任意实现了 Action 接口的动作 (睡觉啦... 玩耍啦... 旅行啦....). 这里的要点是 BeautifulGirl 没有与任何特定的 Action 发生耦合. BeautifulGirl 只需要的是一个实现 Action 接口就行, 对象本身只是通过接口(而非具体实现或初始化过程) 来表明依赖关系, 那么这种依赖就能够在 BeautifulGirl 不知情的情况下替换不同的具体动作. 好了我们现在明白了 DI 进行依关系解耦的原理了, 下面我们看一下如何在 Spring 中应用 DI. example4 实例源码下载
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
- <bean class="com.jimisun.spring.example4.BeautifulGirl" id="beautifulGirl">
- <constructor-arg ref="action"/>
- </bean>
- <bean class="com.jimisun.spring.example4.SleepAction" id="action"></bean>
- </beans>
- /**
- * @Author:jimisun
- * @Description:
- * @Date:Created in 07:53 2018-09-27
- * @Modified By:
- */
- public class Main {
- public static void main(String[] args) {
- ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("Spring.xml");
- BeautifulGirl beautifulGirl = (BeautifulGirl) context.getBean("beautifulGirl");
- beautifulGirl.action();
- context.close();
- }
- }
这样执行 Main 方法, 从 Context 中获取 BeautifulGirl 实例执行 action 方法. 当然 Spring 提供了基于 Java 的配置, 可作为 xml 配置文件的代替方案 example5 实例源码下载
- /**
- * @Author:jimisun
- * @Description:
- * @Date:Created in 08:40 2018-09-27
- * @Modified By:
- */
- @Configuration
- public class SpringConfig {
- @Bean
- public SleepAction sleepAction() {
- return new SleepAction();
- }
- @Bean
- public BeautifulGirl beautifulGirl() {
- return new BeautifulGirl(sleepAction());
- }
- }
只不过 Spring 的上下文的实现应该使用 AnnotationConfigApplicationContext 进行加载配置
- /**
- * @Author:jimisun
- * @Description:
- * @Date:Created in 07:53 2018-09-27
- * @Modified By:
- */
- public class Main {
- public static void main(String[] args) {
- ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
- SleepAction action = applicationContext.getBean(SleepAction.class);
- action.action();
- }
- }
3. 基于切面和惯例进行声明式编程
现在我们已经明白 DI 能够将互相协作的软件保持松耦合, 而面向切面编程 (aspect-oriented-programming,AOP) 可以将遍布应用各处的功能分离出来形成可从用的组件. 我们仍然使用上面的例子, BeautifulGirl 随心所欲的执行各种动作真的没问题吗? 如果可爱的小女孩执行的动作是去河边玩耍, 吃一些危险的东西呢? 那么我们势必需要一个家长 (Parent 类) 进行监督小女孩的动作是否是安全的, 下面我们来看一下 Parent 类. example6 实例源码下载
- /**
- * @Author:jimisun
- * @Description:
- * @Date:Created in 09:32 2018-09-27
- * @Modified By:
- */
- public class Parent {
- public void check() {
- System.out.println("检查动作是否安全.......");
- }
- }
非常简单! Parent(家长类)只有一个方法就是 check, 那么现在就让 Parent 对 BeautifulGirl 的执行动作进行检查吧.
- <bean class="com.jimisun.spring.example6.BeautifulGirl" id="beautifulGirl">
- <constructor-arg ref="action"/>
- <constructor-arg ref="parent"/>
- </bean>
- <bean class="com.jimisun.spring.example6.SleepAction" id="action"></bean>
- <bean class="com.jimisun.spring.example6.Parent" id="parent"></bean>
- </beans>
- /**
- * @Author:jimisun
- * @Description:
- * @Date:Created in 07:44 2018-09-27
- * @Modified By:
- */
- public class BeautifulGirl implements Girl {
- private Action action;
- private Parent parent;
- public BeautifulGirl(Action action, Parent parent) {
- this.action = action;
- this.parent = parent;
- }
- @Override
- public void action() {
- parent.check();
- action.action();
- }
- }
我们非常聪明, 使用了 DI 将 Parent 类注入到了 BeautifulGirl 类中, 在 BeautifulGirl 执行 action 动作之前执行 parent.check()方法, 这样我们要的效果就达到了. 等等.... 好像有什么不对的地方?
管理 Parent 家长的 check 动作真的是美丽的小女孩的职责吗?
将 Parent 家长注入到美丽的小女孩类中不是将代码复杂化了吗?
我们需不需要一个不需要家长注入的美丽的小女孩呢?
如果注入的 Parent 为 NULL 我们是否应该在美丽的小女孩中进行校验呢?
真的是太糟糕了, 注入一个 Parent(家长)将会产生那么多的问题, 为什么呢? 因为 Parent 类的业务于 BeautifulGirl 无关; BeautifulGirl 将会承担 Parent 类的职责.
在一个项目中, 很多系统服务都会分布到各个业务模块中, 这使得业务模块的逻辑变得十分复杂, 而使用 AOP 能够使这些服务模块化, 并以声明式的方式将他们应用到他们所需要影响的组件中, 使得这些组件将会具有更高的内聚性并且更加关注自身的业务逻辑, 完全不需要了解系统服务所带来的复杂性.
下面我们使用 SpringAOP 对上面代码进行改造 example7 实例源码下载
- <!-- 声明 Bean-->
- <bean class="com.jimisun.spring.example7.Parent" id="parent"></bean>
- <!-- 声明切面 -->
- <aop:config>
- <aop:aspect ref="parent">
- <aop:pointcut id="girlAction" expression="execution(* com.jimisun.spring.example7.Action.*(..))"/>
- <aop:before pointcut-ref="girlAction" method="check"/>
- </aop:aspect>
- </aop:config>
- /**
- * @Author:jimisun
- * @Description:
- * @Date:Created in 07:44 2018-09-27
- * @Modified By:
- */
- public class BeautifulGirl implements Girl {
- private Action action;
- public BeautifulGirl(Action action) {
- this.action = action;
- }
- @Override
- public void girlAction() {
- action.action();
- }
- }
我们只需要在 Spring 配置文件中声明 Parent 为 Spring Bean, 然后将配置在 SpringAOP 中即可, 我们可以发现 BeautifulGirl 类中没有发现任何关于 Parent 的信息, 这就是 AOP 的魅力所在 -- 以声明的方式将组件应用到他们所需要影响的组件中!
4. 通过切面和模板减少样版式代码
在通过 JavaAPI 进行编程, 我们经常会编写很多重复的代码例如 JDBC 访问数据库, JMS,JNDI 等场景下会重复编写大量的样版式代码, 而 Spring 皆在通过模板封装来消除模板式代码, 例如 Spring 针对 JDBC 访问数据库进行封装的 JdbcTemplate 等, 这里就是 Spring 使用封装的模板来减少 JavaAPI 样版式代码. example8 实例源码下载
- /**
- * @Author:jimisun
- * @Description:
- * @Date:Created in 11:13 2018-09-27
- * @Modified By:
- */
- public class Main {
- public static void main(String[] args) {
- JdbcTemplate jdbcTemplate = new JdbcTemplate();
- jdbcTemplate.execute("select * from user");
- }
- }
非常感谢大家耐心能看到这里, 在本文中我尽可能地详细阐述 Spring 使如何简化 Java 开发? 遵循哪些策略? 以及为什么遵循的好处.
Java 开发之上帝之眼系列教程其他文章
Java 开发之上帝之眼系列教程前言和章节目录汇总
来源: https://www.cnblogs.com/jimisun/p/9712174.html