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> -->

Spring IoC和AOP的扩展

 

.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>

Spring IoC和AOP的扩展

 

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>