Spring笔记 #01# 一个小而生动的IOC例子代码
例子中仅包含两种类:英雄类Hero和武器类Weapon。
- 演示DI:给Hero初始化Weapon
- 演示AOP:法师是一个英雄,当他发动攻击的时候需要念咒语,只有咒语正确才能施展魔法。通过定义一个切面来检验咒语的正确性(假设咒语必须要符合某种公共的标准。。。。。)
代码结构:
Spring容器的最小可用依赖
- Spring的核心是一个IOC容器,包含两个基础模块:context以及bean(必要)
- 添加AspectJ相关依赖用于支持AOP(必要)
- 添加Log4j依赖方便输出(可选)
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>sample</groupId> <artifactId>spring</artifactId> <version>1.0-SNAPSHOT</version> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <!-- -source 1.5 中不支持 try-with-resources--> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <!-- Use the latest version whenever possible. --> <spring.version>5.1.3.RELEASE</spring.version> <log4j.version>2.11.1</log4j.version> <aspectj.version>1.9.2</aspectj.version> </properties> <dependencies> <!-- https://mvnrepository.com/artifact/org.springframework/spring-context --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-beans --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>${log4j.version}</version> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-api --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>${log4j.version}</version> </dependency> <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>${aspectj.version}</version> </dependency> <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>${aspectj.version}</version> </dependency> </dependencies> </project>
用XML定义元数据
★主配置文件:
<?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.xsd"> <import resource="bean/weapons.xml"/> <import resource="bean/heroes.xml"/> </beans>
★子配置文件1:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="mySword" class="sample.spring.iocbasis.weapon.Sword"/> <bean id="myMagicBook" class="sample.spring.iocbasis.weapon.MagicBook"/> <aop:config> <aop:aspect ref="myMagicBook"> <aop:pointcut id="mageAttack" expression="execution(* sample.spring.iocbasis.hero.Mage.attack(String))" /> <aop:around pointcut-ref="mageAttack" method="magicLimit" /> </aop:aspect> </aop:config> </beans>
★子配置文件2,IDEA可能会报错说找不到引用,但其实是Ok的。注意不要重复import一个配置文件,这会导致重复定义bean或者切面:
<?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.xsd"> <bean id="iocWarrior" class="sample.spring.iocbasis.hero.Warrior"> <constructor-arg ref="mySword" /> </bean> <bean id="iocMage" class="sample.spring.iocbasis.hero.Mage"> <constructor-arg ref="myMagicBook" /> </bean> </beans>
实例化容器&使用容器
★程序入口:
package sample.spring.iocbasis; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import sample.spring.iocbasis.hero.Hero; import sample.spring.iocbasis.hero.Mage; import sample.spring.iocbasis.hero.Warrior; import sample.spring.iocbasis.weapon.MagicBook; import sample.spring.iocbasis.weapon.Sword; public class MyTest { public static void main(String[] args) { System.out.println("===========手动调用setter方法注入================="); Warrior warrior = new Warrior(); warrior.attack(null); warrior.setWeapon(new Sword()); warrior.attack(null); System.out.println("===========手动调用构造器方法注入================="); Warrior warrior2 = new Warrior(new Sword()); warrior2.attack(null); System.out.println("===========直接从IOC容器中获得事先组装好的对象================="); ApplicationContext context = new ClassPathXmlApplicationContext("\\spring\\config.xml"); Warrior iocWarrior = context.getBean("iocWarrior", Warrior.class); iocWarrior.attack(null); System.out.println("===========通过动态代理增强方法================="); Hero iocMage = context.getBean("iocMage", Hero.class); iocMage.attack("hello world."); iocMage.attack("hlo worl."); System.out.println("===========绕过动态代理================="); new Mage(new MagicBook()).attack("hlo worl."); } } /* ===========手动调用setter方法注入================= Warrior{no=1}用WoodenStick{}发起了一次攻击。 Warrior{no=1}用Sword{no=1}发起了一次攻击。 ===========手动调用构造器方法注入================= Warrior{no=2}用Sword{no=2}发起了一次攻击。 ===========直接从IOC容器中获得事先组装好的对象================= Warrior{no=3}用Sword{no=3}发起了一次攻击。 ===========通过动态代理增强方法================= Mage{no=1}试图发动一次魔法攻击,准备校验咒语【hello world.】正确性 ... Mage{no=1}用MagicBook{no=1}发起了一次攻击 Mage{no=1}试图发动一次魔法攻击,准备校验咒语【hlo worl.】正确性 ... Mage{no=1}的咒语念错了,魔法发动失败 ... ===========绕过动态代理================= Mage{no=2}用MagicBook{no=2}发起了一次攻击 */
唯一能看出“第三方依赖痕迹”的类:
package sample.spring.iocbasis.weapon; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.aspectj.lang.ProceedingJoinPoint; public class MagicBook implements Weapon { private static final Logger LOGGER = LogManager.getLogger(); private static int count = 0; private int no = ++count; @Override public void attack() { } public void magicLimit(ProceedingJoinPoint jp) { try { Object obj = jp.getThis(); String spell = String.valueOf(jp.getArgs()[0]); LOGGER.info("{}试图发动一次魔法攻击,准备校验咒语【{}】正确性 ...", obj, spell); if ("hello world.".equals(spell)) { jp.proceed(); } else { LOGGER.info("{}的咒语念错了,魔法发动失败 ...", obj); } } catch (Throwable throwable) { throwable.printStackTrace(); } } @Override public String toString() { return "MagicBook{" + "no=" + no + '}'; } }
其它类:
package sample.spring.iocbasis.hero; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import sample.spring.iocbasis.weapon.Weapon; import sample.spring.iocbasis.weapon.WoodenStick; public class Warrior implements Hero { private static final Logger LOGGER = LogManager.getLogger(); private static int count = 0; private int no = ++count; private Weapon weapon; public Warrior() { weapon = new WoodenStick(); } public Warrior(Weapon weapon) { this.weapon = weapon; } public void setWeapon(Weapon weapon) { this.weapon = weapon; } @Override public void attack(String sth) { LOGGER.info("{}用{}发起了一次攻击。", this, weapon); weapon.attack(); } @Override public String toString() { return "Warrior{" + "no=" + no + '}'; } }
package sample.spring.iocbasis.hero; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import sample.spring.iocbasis.weapon.Weapon; public class Mage implements Hero { private static final Logger LOGGER = LogManager.getLogger(); private static int count = 0; private int no = ++count; private Weapon weapon; public Mage(Weapon weapon) { this.weapon = weapon; } @Override public void attack(String spell) { LOGGER.info("{}用{}发起了一次攻击", this, weapon); } @Override public String toString() { return "Mage{" + "no=" + no + '}'; } }
package sample.spring.iocbasis.weapon; public class Sword implements Weapon { private static int count = 0; private int no = ++count; @Override public void attack() { } @Override public String toString() { return "Sword{" + "no=" + no + '}'; } }
package sample.spring.iocbasis.weapon; public class WoodenStick implements Weapon { @Override public void attack() { } @Override public String toString() { return "WoodenStick{}"; } }
package sample.spring.iocbasis.hero; public interface Hero { void attack(String sth); }