Spring IoC和AOP的扩展

Spring IoC和AOP的扩展

IOC解决了对象的创建 控制反转 不需要再写实现类
DI属性的赋值 依赖注入
aop 面向切面编程

IOC理解
对象的生命周期管理交给了Spring,对象的属性的注入(DI)也交给Spring来管理。(IoC容器/Spring容器 -> 面向bean编程)

AOP理解
在不改变原有代码的基础上,采用代理机制动态在程序运行过程中添加一系列的功能(将公共的功能集中到一起)。

1. 掌握不同的依赖注入方式(DI-IoC)

1.1 掌握设值注入(最重要)-不同数据类型

设值注入,这是我们在Spring应用最多且最广的一种依赖注入方式,非常符合我们以前的开发习惯。基于setter方法来实现依赖注入。(setter强烈推荐你别自己写,让工具帮你生成!)


<!-- User -->
	<bean id="user" class="cn.kgc.demo1.User">
		<property name="username" value="黑色"></property>
	</bean>
	
<bean id="testEntity" class="cn.bdqn.demo2.TestEntity">
<!-- TestEntity bean组件 -->
设值注入applicationContext.xml里面的
在xml中不能出现特殊符号的 > 
<!-- 特殊字符值1 -->
<property name="specialCharacter1" value="1&gt;2"></property>
<!-- 特殊字符值2 -->
		<property name="specialCharacter2">
			<value><![CDATA[1>2]]></value>
		</property>
都是1>2

<!--对象类型 方式1外部bean引入-->

		<property name="innerBean" ref="user"></property>
	



<!--对象类型  方式2 内部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>

<!-- 空字符串1 -->
		<property name="emptyValue" value=""></property>
	<!-- 空字符串2 -->
	<!-- 	<property name="emptyValue">
			<value></value>
		</property>		
   -->
		<!--空值 -->
		<!-- 这个输出的是字符串的null  不对
		<property name="nullValue" value="null"></property>
		 --> 
		<property name="nullValue">
			<null></null>或直接写成<null/>
		</property>
	</bean>


注入空字符串:[]
注入null值:null

public class TestEntity {
	private String specialCharacter1; // 特殊字符值1
	private String specialCharacter2; // 特殊字符值2
	private User innerBean; // JavaBean类型
	private List<String> sportList; // List类型
	private String[] array; // 数组类型
	private Set<String> set; // Set类型
	private Map<String, String> map; // Map类型
	private Properties props; // Properties类型
	private String emptyValue; // 注入空字符串值
	private String nullValue = "init value"; // 注入null值

自己加getset方法
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() {	
	}
	
	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">
    
		<constructor-arg value="12" name="age"/>
		<constructor-arg value="小明"/>
		<constructor-arg ref="user"/>
</bean>	
	<bean id="user" class="cn.kgc.demo2.User">
		<property name="username" value="小明"></property>
	</bean>
	

代码块二:
public class UserService {
	private String username;	
	// 单个参数构造方法
		public UserService(String username) {
			this.username = username;
		}
public UserService() {}	
	public void test() {
		System.out.println("用户名为:"+username);
	}

}

构造注入:单个参数构造方法
applicationContext.xml
<bean id="userService" class="demo2.UserService">
	  <constructor-arg value="小明"/>
	</bean>

代码块三:
public class UserService {
	private String username;
	private User user;	
	private int age;	
	// 多个不同类型参数的构造方法
		public UserService(User user,String username) {
			this.user = user;
			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="demo2.UserService">
		<constructor-arg value="username的值为黑色"/>
		<constructor-arg ref="user"/>
</bean>
	
<bean id="user" class="demo2.User">
		<property name="username" value="小明"></property>
</bean>

代码块四:
package demo2;

public class UserService {
	private String username;
	private User user;
	private int age;	
	public UserService(String username,int age) {	
		this.username = username;
		this.age = age;
	}	
public UserService() {		}
	public void test() {
		System.out.println("用户名为:"+username);
		System.out.println("用户年龄为:"+age);
	}
}


<!-- 下面的index  type  name属性了解即可 -->
		<!-- <constructor-arg value="12" index="2"/> -->
		<!-- <constructor-arg value="12" type="int"/> -->
		<!-- 带参构造方法注入 -->
		<!-- 
			1.如果构造方法的参数都是不同类型,那么在进行编写<constructor-arg>给参数赋值时,不需要区分顺序。
			2.如果构造方法的参数有相同类型的或者不同类型但是却可以赋值的,那么它会按照你赋值的顺序依次给其参数注值。
					例如: 参数int    11
						 参数String  11
				2.1 我们可以使用index属性 控制值的注入位置  index索引(在构造方法中的参数的索引)0开始
				2.2 我们可以使用type属性 控制值的注入位置  int 可以接受123这种值   String也可以接受123这种值 所以你可以进行区分。
		 -->
		 <bean id="userService" class="demo2.UserService">
	<constructor-arg value="黑色" index="0"/> 	
		<constructor-arg value="12" index="1"/> 	
</bean>

在这里插入图片描述

1.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 + 注解 -> 纯注解
有了spring以后就不需要写实现类了 因为我们采用了ioc注入
创建bean以后 就会帮助我们来创建对象了

以前我们是这样配置对象  但是我们如果有更多的dao 配置起来比较麻烦  class里面写的是具体的类信息 引入了注解
<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>

在这里插入图片描述

package dao;

import demo1.User;

public interface UserDao {
	
	int add(User user)throws Exception;

}

package dao;

import demo1.User;

public class UserDaoImpl implements UserDao{

	public int add(User user) throws Exception {
		System.out.println("用户添加成功");
		return 1;
	}

}

package service;

import dao.UserDao;
import demo1.User;

public interface UserService {
	
	public boolean add(User user)throws Exception;

}

(1)未使用注解

package service;

import org.springframework.beans.factory.annotation.Autowired;

import dao.UserDao;
import demo1.User;

public class UserServiceImpl implements UserService{

	
	private UserDao userDao;
	
	public boolean add(User user) throws Exception {
		boolean flag=false;
		if(userDao.add(user)>0) {
			return true;
		}
		return flag;
	}

	public UserDao getUserDao() {
		return userDao;
	}

	public void setUserDao(UserDao userDao) {
		this.userDao = userDao;
	}

	
	
	

}

package demo1;

import org.springframework.context.support.AbstractXmlApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import service.UserService;

public class Test{

	public static void main(String[] args) throws Exception {
		
		// 1.加载核心配置文件
		AbstractXmlApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
		
		// 2.获取对象  IOC  DI  你想获取谁的对象  就使用对应的配置文件中配置的id来获取即可
		UserService userService=(UserService) ac.getBean("userService","UserServie.class");
		
		User user = new User("heise1");
		
		boolean flag = userService.add(user);
		
		if(flag) {
			System.out.println("添加成功");
		}else {
			System.out.println("添加失败");
		}
	}

}

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:aop="http://www.springframework.org/schema/aop"
	   xmlns:p="http://www.springframework.org/schema/p"
	   xmlns:context="http://www.springframework.org/schema/context"
	   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
	   http://www.springframework.org/schema/aop
	   http://www.springframework.org/schema/aop/spring-aop.xsd
	   http://www.springframework.org/schema/context
	   http://www.springframework.org/schema/context/spring-context.xsd">

	<bean id="userDao" class="dao.UserDaoImpl"></bean>

	<bean id="userService" class="service.UserServiceImpl">
		<property name="userDao" ref="userDao"></property> 
	</bean> 
	
	
</beans>

(2)使用注解autowired

package service;

import org.springframework.beans.factory.annotation.Autowired;

import dao.UserDao;
import demo1.User;

public class UserServiceImpl implements UserService{

	//使用注解@Autowired  就不需要加getset方法   配置文件中 property name="userDao" ref="userDao"这个就不要写了,写了反而报错 ,同时配置文件中还要加component-scan
	@Autowired
	private UserDao userDao;
	
	public boolean add(User user) throws Exception {
		boolean flag=false;
		if(userDao.add(user)>0) {
			return true;
		}
		return flag;
	}

/*	public UserDao getUserDao() {
		return userDao;
	}

	public void setUserDao(UserDao userDao) {
		this.userDao = userDao;
	}

	*/
	
	

}

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:aop="http://www.springframework.org/schema/aop"
	   xmlns:p="http://www.springframework.org/schema/p"
	   xmlns:context="http://www.springframework.org/schema/context"
	   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
	   http://www.springframework.org/schema/aop
	   http://www.springframework.org/schema/aop/spring-aop.xsd
	   http://www.springframework.org/schema/context
	   http://www.springframework.org/schema/context/spring-context.xsd">

	<bean id="userDao" class="dao.UserDaoImpl"></bean>

	<bean id="userService" class="service.UserServiceImpl">
	
	<!-- 	<property name="userDao" ref="userDao"></property>  -->
	</bean> 
	  <!-- 扫描包中注解标注的类 -->
	  <context:component-scan base-package="service"></context:component-scan>
</beans>
3.1 实现IoC

以下注解能帮你实现自动生成bean:(IoC)

@Controller 表现层

@Service 业务逻辑层

@Repository 数据访问层 仓库 数据存储上 dao层

@Component 组件/部件(适合于非三层架构的类) 通用的

//<bean id="userDao" class="cn.kgc.demo5.dao.impl.UserDaoImpl"></bean>
//注意小写("userDao")
@Repository("userDao")
public class UserDaoImpl implements UserDao {
   // 省略部分代码
}


//<bean id="userService" class="cn.kgc.demo5.service.impl.UserServiceImpl">
//注意小写("userService")
@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
<?xml version="1.0" encoding="UTF-8"?>
 <beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:aop="http://www.springframework.org/schema/aop"
	   xmlns:p="http://www.springframework.org/schema/p"
	   xmlns:context="http://www.springframework.org/schema/context"
	   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
	   http://www.springframework.org/schema/aop
	   http://www.springframework.org/schema/aop/spring-aop.xsd
	   http://www.springframework.org/schema/context
	   http://www.springframework.org/schema/context/spring-context.xsd">
	<!--组件 注解扫描-->
    <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 适合于普通值注入

增删改的事务注解transactional

@Resource装配顺序:

①如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常。

②如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常。

③如果指定了type,则从上下文中找到类似匹配的唯一bean进行装配,找不到或是找到多个,都会抛出异常。

④如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配。

@Resource的作用相当于@Autowired,只不过@Autowired按照byType自动注入。
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;
	}
	
}
<!--启用Ioc注解扫描-->
<context:component-scan base-package="cn.kgc.demo6"></context:component-scan>
<!-- 启用AOP注解 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值