Spring IoC和AOP的扩展
1. 掌握不同的依赖注入方式(DI-IoC)
1.1 掌握设值注入(最重要)-不同数据类型
设值注入,这是我们在Spring应用最多且最广的一种依赖注入方式,非常符合我们以前的开发习惯。基于setter方法来实现依赖注入。(setter强烈推荐你别自己写,让工具帮你生成!)
<!-- TestEntity bean组件 --> 设值注入applicationContext.xml里面的 在xml中不能出现特殊符号的 > <!-- 特殊字符值1 --> <property name="specialCharacter1" value="1>2"></property> <!-- 特殊字符值2 --> <property name="specialCharacter2"> <value><![CDATA[1>2]]></value> </property> 都是1>2 <!--对象类型 外部bean引入--> <bean id="testEntity" class="cn.kgc.demo1.TestEntity"> <property name="innerBean" ref="user"></property> </bean> <!-- User --> <bean id="user" class="cn.kgc.demo1.User"> <property name="username" value="黑色"></property> </bean> <!--对象类型 内部bean --> <property name="innerBean"> <!--不用在加id 内部bean只能用一次--> <bean class="cn.kgc.demo1.User"> <property name="username" value="黑色"></property> </bean> </property> 外部bean写了id说明他可以被重复用 <!--集合类型 --> <property name="sportList"> <list> <value>游泳</value> <value>下棋</value> </list> </property> <!--数组类型 --> <property name="array"> <array> <value>下棋</value> <value>游泳</value> </array> </property> <!-- set集合 --> <property name="set"> <set> <value>唱</value> <value>跳</value> </set> </property> <!--map集合 未来多个键值对 就写多个entrty--> <property name="map"> <map> <entry> <key> <value>CN</value> </key> <value>中国</value> </entry> </map> </property> properties HashTable里面的一个子类 <!-- properties类型--> <property name="props"> <props> <prop key="Us">美国</prop> </props> </property> <!-- 空字符串 --> <property name="emptyValue" value=""></property> <!--空值 --> <!-- 这个输出的是字符串的null 不对 <property name="nullValue" value="null"></property> --> <property name="nullValue"> <null></null>或直接写成<null/> </property> </bean>
1.2 掌握构造注入
以前我们测试他的时候 是提供一下get+set方法 用的是设值注入
现在 写个构造(建议你把无参也写出来)
基于构造方法(带参构造)实现注入!
之前的设值注入使用的是无参构造(默认调用)。
public class UserService { private String username; private User user; private int age; // 兼容类型的冲突问题 例如:12既可以存储为字符串 也可以存储为数值 // 出现兼容性问题时 它会按照构造参数上的顺序进行赋值 public UserService(User user,String username,int age) { this.user = user; this.username = username; this.age = age; } // 多个不同类型参数的构造方法 /*public UserService(User user,String username) { this.user = user; this.username = username; }*/ // 单个参数构造方法 /*public UserService(String username) { this.username = username; }*/ public UserService() { } public void test() { System.out.println("用户名为:"+username); System.out.println("用户年龄为:"+age); System.out.println("User的用户名为:"+user.getUsername()); } }
<bean id="userService" class="cn.kgc.demo2.UserService"> <!-- 下面的index type name属性了解即可 --> <!-- <constructor-arg value="12" index="2"/> --> <!-- <constructor-arg value="12" type="int"/> --> <constructor-arg value="12" name="age"/> <constructor-arg value="小明"/> <constructor-arg ref="user"/> </bean> <!-- <bean id="userService" class="cn.kgc.demo2.UserService"> 构造注入:多个不同类型参数的构造方法 <constructor-arg value="小明"/> <constructor-arg ref="user"/> </bean> --> <bean id="user" class="cn.kgc.demo2.User"> <property name="username" value="小明"></property> </bean> <!-- <bean id="userService" class="cn.kgc.demo2.UserService"> 构造注入:单个参数构造方法 <constructor-arg value="小明"/> </bean> -->
.3 掌握p命名空间注入
p命名空间注入它是基于设值注入,写法上简洁一些。内部bean 太麻烦 优化 p命名空间注入
xmlns:p="http://www.springframework.org/schema/p" 以前:<bean id="userService" class="cn.kgc.demo3.UserService"> <property name="userName" value="黑色UserService"></property> <property name="User"> <bean class="cn.kgc.demo3.User"> <property name="username" value="黑色User"></property> </bean> </property> </bean> 现在: 对于直接量(基本数据类型 字符串) p:属性名="属性值" 对于引用Bean(对象)的属性 p:属性名-ref="Bean的id" <bean id="userService" class="cn.kgc.demo3.UserService" p:userName="黑色UserService" p:user-ref="user"/> <bean id="user" class="cn.kgc.demo3.User"> <property name="username" value="黑色User"></property> </bean>
2. 掌握更多的增强处理的类型(AOP)
异常类配置:
<!--将我们自己配置的增强处理类 织入到指定的方法上(切点表达式) --> <bean id="随便起1 保证唯一" class="增强类全类名" /> <aop:config> <!--配置切点选择器:选择匹配的方法 id唯一 --> <aop:pointcut expression="execution(表达式)" id="随便起2 保证唯一" /> <!-- 配置切面 引入增强处理类 配置增强处理方法 --> <aop:aspect ref="随便起1"> <aop:before method="前置增强类方法名" pointcut-ref="随便起2" /> <aop:after-returning method="后置增强类方法名" returning="返回值名" pointcut-ref="随便起2" /> <aop:after-throwing method="异常抛出增强方法名" throwing="抛出异常的名" pointcut-ref="随便起2" /> <!--最终增强--> <aop:after method="afterMethod" pointcut-ref="myPointCut" /> </aop:aspect> </aop:config>
前置增强
后置增强
异常抛出增强:(出现异常的话 后置增强就不会执行)
// 异常抛出增强 当异常出现之后 会执行的增强 public void throwsExceptionMethod(JoinPoint jp,Exception e) { Signature signature = jp.getSignature(); // 获取方法名 String methodName = signature.getName(); logger.error("<=="+methodName+"方法执行出现异常<==异常信息为:"+e); }
pointcut-ref="logPointCut" 表示引用上面的切面规则 还有一个poingcut属性 如果你不想引用上面的匹配规则 就自己写 在配置切面的时候配置新的匹配规则(还是和上面的expression 里面的一样) 此处省略掉部分代码 <aop:after-throwing method="throwsExceptionMethod" throwing="e" pointcut-ref="logPointCut"/>
最终增强
// 最终增强 finally执行内容 public void afterMethod(JoinPoint jp) { Signature signature = jp.getSignature(); // 获取方法名 String methodName = signature.getName(); logger.error("<=="+methodName+"方法正在执行最终处理内容"); }
<aop:after method="afterMethod" pointcut-ref="logPointCut"/>
环绕增强:上述所有的增强整合
// 环绕增强 public Object aroundMethod(ProceedingJoinPoint jp) { Signature signature = jp.getSignature(); String methodName = signature.getName(); String argStr = Arrays.toString(jp.getArgs()); // 前置增强 logger.info("==>正在执行"+methodName+"方法==>方法参数为:"+argStr); // 此返回值要对应上对应的方法的返回值类型 Object returnResult = null; try { // 执行目标方法 returnResult = jp.proceed(); // 后置增强 logger.info("<=="+methodName+"方法执行结束<==方法返回值为:"+returnResult); } catch (Throwable e) { e.printStackTrace(); // 异常抛出增强 logger.error("<=="+methodName+"方法执行出现异常<==异常信息为:"+e); }finally { // 最终增强 logger.error("<=="+methodName+"方法正在执行最终处理内容"); } return returnResult; }
<aop:around method="aroundMethod" pointcut-ref="logPointCut"/>
3. 掌握注解实现IoC和AOP
XML(更接近于基础实现) -> XML + 注解 -> 纯注解
以前我们是这样配置对象 但是我们如果有更多的dao 配置起来比较麻烦 引入了注解 <bean id="userDao" class="cn.kgc.demo5.dao.impl.UserDaoImpl"></bean> <bean id="userService" class="cn.kgc.demo5.service.impl.UserServiceImpl"> <property name="userDao" ref="userDao"></property> </bean>
3.1 实现IoC
以**解能帮你实现自动生成bean:(IoC)
@Controller 表现层
@Service 业务逻辑层
@Repository 数据访问层 仓库 数据存储上 dao层
@Component 组件/部件(适合于非三层架构的类) 通用的
//<bean id="userDao" class="cn.kgc.demo5.dao.impl.UserDaoImpl"></bean> @Repository("userDao") public class UserDaoImpl implements UserDao { // 省略部分代码 } //<bean id="userService" class="cn.kgc.demo5.service.impl.UserServiceImpl"> @Service("userService") public class UserServiceImpl implements UserService { //@Autowired //自动装配注入 按照名字和类型查找 名字不一样就按照类型找 @Resource //按照名字和类型查找 @Resource(name="")按照指定的名字进行查找 private UserDao userDao; 在 applicationContext.xml配置一下Context xmlns:context="http://www.springframework.org/schema/context" http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd base-package指定扫描包 自动扫描包下的所有内容 包括子包下的 扫描的如果还有别的包 逗号隔开 扫描所有的包 cn.kgc <beans xmlns="http://www.springframework.org/schema/beans" 省略部分代码> <context:component-scan base-package="cn.kgc.demo5"></context:component-scan> </beans>
以**解可以实现自动依赖注入:(DI)
@Autowired 适合于对象属性注入 它和Resource都可以实现按照名称和类型来注入(自动查找)。 位于org.springframework.beans.factory.annotation.Autowired包中 不需要你写set方法 根据你的业务判断你的get set方法还要不要
@Resource 适合于对象属性注入 javax.annotation.Resource;
@Value 适合于普通值注入
3.2 实现AOP
@Component // <bean id="loggerIncreseClass" class="cn.kgc.demo4.increse.LoggerIncreseClass"/> @Aspect // <aop:aspect ref="loggerIncreseClass"> public class LoggerIncreseClass { private Logger logger = Logger.getLogger(LoggerIncreseClass.class); /*使用注解 未来如果多个切点一样 我们还要配置多个 所以我们可以写一个方法*/ @Pointcut("execution(* cn.kgc.demo6.UserService.*(..))") public void pointCut() {}; // 环绕增强 // @Around("execution(* cn.kgc.demo6.UserService.*(..))") @Around("pointCut()") public Object aroundMethod(ProceedingJoinPoint jp) { Signature signature = jp.getSignature(); String methodName = signature.getName(); String argStr = Arrays.toString(jp.getArgs()); // 前置增强 logger.info("==>正在执行"+methodName+"方法==>方法参数为:"+argStr); // 此返回值要对应上对应的方法的返回值类型 Object returnResult = null; try { // 执行目标方法 returnResult = jp.proceed(); // 后置增强 logger.info("<=="+methodName+"方法执行结束<==方法返回值为:"+returnResult); } catch (Throwable e) { e.printStackTrace(); // 异常抛出增强 logger.error("<=="+methodName+"方法执行出现异常<==异常信息为:"+e); }finally { // 最终增强 logger.error("<=="+methodName+"方法正在执行最终处理内容"); } return returnResult; } }
<context:component-scan base-package="cn.kgc.demo6"></context:component-scan> <!-- 启用AOP注解 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy>