Spring 教程02
spring-2 1. Xml <!-- \src\applicationContext-annotation.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" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <!-- 配置自动扫描的包 --> <context:component-scan base-package="com.atguigu.spring.ref"></context:component-scan> </beans> <!-- \src\applicationContext-aop.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" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" 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-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <!-- 自动扫描的包 --> <context:component-scan base-package="com.atguigu.spring.aop"></context:component-scan> <!-- 使 AspectJ 的注解起作用 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans> <!-- \src\applicationContext.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"> <!-- 1. 默认情况下, IOC 容器中的 bean 是单例的! 若对象是单例的, 则在创建 IOC 容器时即创建 bean 的实例, 并对 bean 的属性进行初始化. 2. 可以通过 bean 的 scope 属性来修改 bean 的作用域. 若取值为 prototype, 则 bean 为原型的: 每次向容器获取实例, 得到的都是一个新的对象. 而且, 不在创建 IOC 容器时创建 bean 的实例了. 3. IOC 容器中 bean 的生命周期: 3.1 一般地, 讨论 bean 的生命周期, 是建立在 bean 是单例的基础上的. 3.2 可以为 bean 指定 init 和 destroy 方法 3.3 还可以通过 bean 的后置处理器来更加丰富 bean 的生命周期方法(面试时.). --> <bean id="helloWorld" class="com.atguigu.spring.helloworld.HelloWorld" scope="singleton" init-method="init" destroy-method="destroy"> <property name="userName" value="atguigu"></property> </bean> <!-- 1. 在 IOC 容器中配置 bean 之间的关联关系 --> <bean id="userDao" class="com.atguigu.spring.ref.UserDao"></bean> <bean id="userService" class="com.atguigu.spring.ref.UserService"> <property name="userDao" ref="userDao"></property> </bean> <bean id="userAction" class="com.atguigu.spring.ref.UserAction"> <property name="userService" ref="userService"></property> </bean> </beans>
2. Java // \src\com\atguigu\spring\aop\ArithmeticCalculator.java package com.atguigu.spring.aop; public interface ArithmeticCalculator { int add(int i, int j); int sub(int i, int j); int mul(int i, int j); int div(int i, int j); } // \src\com\atguigu\spring\aop\ArithmeticCalculatorImpl.java package com.atguigu.spring.aop; import org.springframework.stereotype.Component; @Component("arithmeticCalculator") public class ArithmeticCalculatorImpl implements ArithmeticCalculator { @Override public int add(int i, int j) { int result = i + j; return result; } @Override public int sub(int i, int j) { int result = i - j; return result; } @Override public int mul(int i, int j) { int result = i * j; return result; } @Override public int div(int i, int j) { int result = i / j; return result; } } // \src\com\atguigu\spring\aop\ArithmeticCalculatorLoggingImpl.java package com.atguigu.spring.aop; public class ArithmeticCalculatorLoggingImpl implements ArithmeticCalculator { @Override public int add(int i, int j) { System.out.println("The method add begins with [" + i + "," + j + "]"); int result = i + j; System.out.println("The method add ends with " + result); return result; } @Override public int sub(int i, int j) { System.out.println("The method sub begins with [" + i + "," + j + "]"); int result = i - j; System.out.println("The method sub ends with " + result); return result; } @Override public int mul(int i, int j) { System.out.println("The method mul begins with [" + i + "," + j + "]"); int result = i * j; System.out.println("The method mul ends with " + result); return result; } @Override public int div(int i, int j) { System.out.println("The method div begins with [" + i + "," + j + "]"); int result = i / j; System.out.println("The method div ends with " + result); return result; } } // \src\com\atguigu\spring\aop\ArithmeticCalculatorLoggingProxy.java package com.atguigu.spring.aop; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Arrays; public class ArithmeticCalculatorLoggingProxy { //要代理的对象 private ArithmeticCalculator target; public ArithmeticCalculatorLoggingProxy(ArithmeticCalculator target) { super(); this.target = target; } //返回代理对象 public ArithmeticCalculator getLoggingProxy(){ ArithmeticCalculator proxy = null; ClassLoader loader = target.getClass().getClassLoader(); Class [] interfaces = new Class[]{ArithmeticCalculator.class}; InvocationHandler h = new InvocationHandler() { /** * proxy: 代理对象。 一般不使用该对象 * method: 正在被调用的方法 * args: 调用方法传入的参数 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String methodName = method.getName(); //打印日志 System.out.println("[before] The method " + methodName + " begins with " + Arrays.asList(args)); //调用目标方法 Object result = null; try { //前置通知 result = method.invoke(target, args); //返回通知, 可以访问到方法的返回值 } catch (NullPointerException e) { e.printStackTrace(); //异常通知, 可以访问到方法出现的异常 } //后置通知. 因为方法可以能会出异常, 所以访问不到方法的返回值 //打印日志 System.out.println("[after] The method ends with " + result); return result; } }; /** * loader: 代理对象使用的类加载器。 * interfaces: 指定代理对象的类型. 即代理代理对象中可以有哪些方法. * h: 当具体调用代理对象的方法时, 应该如何进行响应, 实际上就是调用 InvocationHandler 的 invoke 方法 */ proxy = (ArithmeticCalculator) Proxy.newProxyInstance(loader, interfaces, h); return proxy; } } // \src\com\atguigu\spring\aop\LoggingAspect.java package com.atguigu.spring.aop; import java.util.Arrays; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; /** * AOP 的 helloWorld * 1. 加入 jar 包 * com.springsource.net.sf.cglib-2.2.0.jar * com.springsource.org.aopalliance-1.0.0.jar * com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar * spring-aspects-4.0.0.RELEASE.jar * * 2. 在 Spring 的配置文件中加入 aop 的命名空间。 * * 3. 基于注解的方式来使用 AOP * 3.1 在配置文件中配置自动扫描的包: <context:component-scan base-package="com.atguigu.spring.aop"></context:component-scan> * 3.2 加入使 AspjectJ 注解起作用的配置: <aop:aspectj-autoproxy></aop:aspectj-autoproxy> * 为匹配的类自动生成动态代理对象. * * 4. 编写切面类: * 4.1 一个一般的 Java 类 * 4.2 在其中添加要额外实现的功能. * * 5. 配置切面 * 5.1 切面必须是 IOC 中的 bean: 实际添加了 @Component 注解 * 5.2 声明是一个切面: 添加 @Aspect * 5.3 声明通知: 即额外加入功能对应的方法. * 5.3.1 前置通知: @Before("execution(public int com.atguigu.spring.aop.ArithmeticCalculator.*(int, int))") * @Before 表示在目标方法执行之前执行 @Before 标记的方法的方法体. * @Before 里面的是切入点表达式: * * 6. 在通知中访问连接细节: 可以在通知方法中添加 JoinPoint 类型的参数, 从中可以访问到方法的签名和方法的参数. * * 7. @After 表示后置通知: 在方法执行之后执行的代码. */ //通过添加 @Aspect 注解声明一个 bean 是一个切面! @Aspect @Component public class LoggingAspect { @Before("execution(public int com.atguigu.spring.aop.ArithmeticCalculator.*(int, int))") public void beforeMethod(JoinPoint joinPoint){ String methodName = joinPoint.getSignature().getName(); Object [] args = joinPoint.getArgs(); System.out.println("The method " + methodName + " begins with " + Arrays.asList(args)); } @After("execution(* com.atguigu.spring.aop.*.*(..))") public void afterMethod(JoinPoint joinPoint){ String methodName = joinPoint.getSignature().getName(); System.out.println("The method " + methodName + " ends"); } } // \src\com\atguigu\spring\aop\Main.java package com.atguigu.spring.aop; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Main { public static void main(String[] args) { // ArithmeticCalculator arithmeticCalculator = new ArithmeticCalculatorImpl(); // // arithmeticCalculator = // new ArithmeticCalculatorLoggingProxy(arithmeticCalculator).getLoggingProxy(); // // int result = arithmeticCalculator.add(11, 12); // System.out.println("result:" + result); // // result = arithmeticCalculator.div(21, 3); // System.out.println("result:" + result); ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext-aop.xml"); ArithmeticCalculator arithmeticCalculator = (ArithmeticCalculator) ctx.getBean("arithmeticCalculator"); System.out.println(arithmeticCalculator.getClass().getName()); int result = arithmeticCalculator.add(11, 12); System.out.println("result:" + result); result = arithmeticCalculator.div(21, 3); System.out.println("result:" + result); } } // \src\com\atguigu\spring\helloworld\HelloWorld.java package com.atguigu.spring.helloworld; public class HelloWorld { //字段 private String user; public HelloWorld() { System.out.println("HelloWorld's constructor..."); } //JavaBean 使用 setter 和 getter 来定义属性 public void setUserName(String user) { System.out.println("setUserName:" + user); this.user = user; } public void hello(){ System.out.println("Hello:" + user); } public void init(){ System.out.println("init method..."); } public void destroy(){ System.out.println("destroy method..."); } } // \src\com\atguigu\spring\helloworld\Main.java package com.atguigu.spring.helloworld; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Main { public static void main(String[] args) { //1. 创建 IOC 容器 ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); //2. 从 IOC 容器中获取 bean 实例 HelloWorld helloWorld = (HelloWorld) ctx.getBean("helloWorld"); //3. 调用 bean 的方法 helloWorld.hello(); HelloWorld helloWorld2 = (HelloWorld) ctx.getBean("helloWorld"); System.out.println(helloWorld == helloWorld2); //4. 关闭容器 ctx.close(); } } // \src\com\atguigu\spring\ref\Main.java package com.atguigu.spring.ref; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Main { public static void main(String[] args) { //1. 创建 IOC 容器 ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext-annotation.xml"); UserAction userAction = (UserAction) ctx.getBean("userAction"); userAction.execute(); } } // \src\com\atguigu\spring\ref\UserAction.java package com.atguigu.spring.ref; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; @Controller public class UserAction { private UserService userService; @Autowired public void setUserService(UserService userService) { this.userService = userService; } public void execute(){ System.out.println("execute..."); userService.addNew(); } } // \src\com\atguigu\spring\ref\UserDao.java package com.atguigu.spring.ref; import org.springframework.stereotype.Repository; @Repository public class UserDao { public void save(){ System.out.println("UserDao's save..."); } } // \src\com\atguigu\spring\ref\UserService.java package com.atguigu.spring.ref; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class UserService { @Autowired private UserDao userDao; public void setUserDao(UserDao userDao) { this.userDao = userDao; } public void addNew(){ System.out.println("addNew..."); userDao.save(); } }