Spring总结

Posted lyang-a

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring总结相关的知识,希望对你有一定的参考价值。

Spring

????SSH:Spring . Struts1/2 . Hiberernate

????SSM:Spring . SpringMVC . Mybatis

????Spring框架是由于软件开发的复杂性而创建的。Spring使用的是基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅仅限于服务器端的开发。从简单性、可测试性和松耦合性角度而言,绝大部分Java应用都可以从Spring中受益。

???????◆目的:解决企业应用开发的复杂性

???????◆功能:使用基本的JavaBean代替EJB,并提供了更多的企业应用功能

???????◆范围:任何Java应用

????Spring是一个轻量级**控制反转(IoC)面向切面(AOP)**的容器框架。

起源

???要谈Spring的历史,就要先谈J2EE。J2EE应用程序的广泛实现是在1999年和2000年开始的,它的出现带来了诸如事务管理之类的核心中间层概念的标准化,但是在实践中并没有获得绝对的成功,因为开发效率,开发难度和实际的性能都令人失望。

??曾经使用过EJB开发JAVA EE应用的人,一定知道,在EJB开始的学习和应用非常的艰苦,很多东西都不能一下子就很容易的理解。EJB要严格地实现各种不同类型的接口,类似的或者重复的代码大量存在。而配置也是复杂和单调,同样使用JNDI进行对象查找的代码也是单调而枯燥。虽然有一些开发工作随着xdoclet的出现,而有所缓解,但是学习EJB的高昂代价,和极低的开发效率,极高的资源消耗,都造成了EJB的使用困难。而Spring出现的初衷就是为了解决类似的这些问题。

???Spring的一个最大的目的就是使JAVA EE开发更加容易。同时,Spring之所以与Struts、Hibernate等单层框架不同,是因为Spring致力于提供一个以统一的、高效的方式构造整个应用,并且可以将单层框架以最佳的组合揉和在一起建立一个连贯的体系。可以说Spring是一个提供了更完善开发环境的一个框架,可以为POJO(Plain Ordinary Java Object)对象提供企业级的服务。

???Spring的形成,最初来自Rod Jahnson所著的一本很有影响力的书籍《Expert One-on-One J2EE Design and Development》,就是在这本书中第一次出现了Spring的一些核心思想,该书出版于2002年。另外一本书《Expert One-on-One J2EE Development without EJB》,更进一步阐述了在不使用EJB开发JAVA EE企业级应用的一些设计思想和具体的做法。有时间了可以详细的研读一下。

Spring的初衷:

1、JAVA EE开发应该更加简单。

2、使用接口而不是使用类,是更好的编程习惯。Spring将使用接口的复杂度几乎降低到了零。

3、为JavaBean提供了一个更好的应用配置框架。

4、更多地强调面向对象的设计,而不是现行的技术如JAVA EE。

5、尽量减少不必要的异常捕捉。

6、使应用程序更加容易测试。

Spring的目标:

1、可以令人方便愉快的使用Spring。

2、应用程序代码并不依赖于Spring APIs。

3、Spring不和现有的解决方案竞争,而是致力于将它们融合在一起。

Spring的基本组成:

1、最完善的轻量级核心框架。

2、通用的事务管理抽象层。

3、JDBC抽象层。

4、集成了Toplink, Hibernate, JDO, and iBATIS SQL Maps。

5、AOP功能。

6、灵活的MVC Web应用框架。

Spring架构

技术图片

推荐书籍:Spring in Action

J2EE三层结构的演变

package com.sxt.factory;

import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

public class ObjectFactory {
	
	/**
	 *  ioc  容器
	 *  	key  类的全路径
	 *  	value 类的对象	
	 */
	public static Map<String,Object> ioc = new HashMap<String,Object>();
	
	/**
	 * @Title: getInstance
	 * @author: Mr.T   
	 * @date: 2019年11月20日 上午10:54:28 
	 * @Description: 
	 * 		这种方案不足 ,利用反射的灵活可以创建各种对象,减少工厂的个数.但是  效率堪忧.
	 * 		发现效率低的原因,由于IOC容器没有对象,所以需要使用反射进行创建对象,再放入IOC容器.
	 * 		如果,需要使用时,IOC容器存在需要使用的对象,那么效率不仅仅没有降低,且提高了.
	 * 		当项目启动时,就直接将需要创建的对象,放入IOC容器中
	 * @param <T>
	 * @param cls
	 * @return
	 * @return: T
	 */
	public static <T> T getInstance(Class<T> cls) {
		/**
		 * 每次创建对象都是创建新的对象
		 */
		 T t = null;
		 // 获取类的全路径
		 String key = cls.getName();
		 // 判断对象容器中是否存在   若存在直接取
		 if(ioc.containsKey(key)) {
			 return (T) ioc.get(key);
		 }
		 // 若不存在  则创建一个,返回 ,且将对象放入到IOC容器中
		try {
			t = cls.newInstance();
			ioc.put(key, t);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return t;
	}
	
	public  void init() {
		InputStream in = ObjectFactory.class.getClassLoader().getResourceAsStream("obj.properties");
		Properties prop = new Properties();
		try {
			prop.load(in);
			String dao = prop.getProperty("dao");
			String service = prop.getProperty("service");
			String[] classes = dao.split(",");
			for (int i = 0; i < classes.length; i++) {
				Class<?> cls = Class.forName(classes[i]);
				String name = cls.getName();
				Object obj = cls.newInstance();
				ioc.put(name, obj);
			}
			classes = service.split(",");
			for (int i = 0; i < classes.length; i++) {
				Class<?> cls = Class.forName(classes[i]);
				String name = cls.getName();
				Object obj = cls.newInstance();
				ioc.put(name, obj);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
dao=com.sxt.dao.impl.UserDaoImpl,com.sxt.dao.impl.ClassesDaoImpl
service=com.sxt.service.impl.UserServiceImpl,com.sxt.service.impl.ClassesServiceImpl

Spring应用

???在实际开发中,对象和方法是最基础,最核心的东西.Spring核心只进行对象和方法的管理.对象的管理,在Spring中被称之为IOC/DI-控制反转(Inversion of Control,缩写为IoC).

IOC控制反转:

???将对象的创建初始化的权利,从开发者手中转移到Spring容器.由Spring将程序中需要的对象进行创建和装配.减少了开发者对对象的管理工作.这种模式就被称之为控制反转.

**DI—Dependency Injection,即“依赖注入”**:

  1. IoC的别名,2004年,Martin Fowler探讨了同一个问题,既然IoC是控制反转,那么到底是“哪些方面的控制被反转了呢?”,经过详细地分析和论证后,他得出了答案:“获得依赖对象的过程被反转了”。控制被反转之后,获得依赖对象的过程由自身管理对象变为由IoC容器主动注入。于是,他给“控制反转”取了一个更合适的名字叫做“依赖注入(Dependency Injection,DI)”。他的这个答案,实际上给出了实现IoC的方法:注入。

  2. 所谓依赖注入,就是由IoC容器在运行期间,动态地将某种依赖关系注入到对象之中。

  3. 所以,依赖注入(DI)和控制反转(IoC)是从不同的角度描述的同一件事情,就是指通过引入IoC容器,利用依赖关系注入的方式,实现对象之间的解耦

Spring入门使用

??spring下载地址https://repo.spring.io/webapp/#/artifacts/browse/tree/General/release

  1. 下载jar包

??Spring Framework 5.2.x: JDK 8-14

??Spring Framework 5.1.x: JDK 8-12

??Spring Framework 5.0.x: JDK 8-10

??Spring Framework 4.3.x: JDK 6-8

技术图片

Spring各个jar包作用

??spring-aop:Spring的面向切面编程,提供AOP(面向切面编程)的实现
??spring-aspects:Spring提供的对AspectJ框架的整合
??spring-beans:Spring IOC的基础实现,包含访问配置文件、创建和管理bean等。
??spring-context:在基础IOC功能上提供扩展服务,此外还提供许多企业级服务的支持,有邮件服务、任务调度、JNDI定位,EJB集成、远程访问、缓存以及多种视图层框架的支持。
??spring-context-support:Spring context的扩展支持,用于MVC方面。
??spring-core:Spring的核心工具包
??spring-expression:Spring表达式语言
??spring-instrument:Spring对服务器的代理接口
??spring-instrument-tomcat:Spring对tomcat连接池的集成
??spring-jdbc:对JDBC 的简单封装
??spring-jms:为简化jms api的使用而做的简单封装
??spring-messaging:消息支持相关包
??spring-orm:整合第三方的orm实现,如hibernate,ibatis,jdo以及spring 的jpa实现
??spring-oxm:Spring对于object/xml映射的支持,可以让JAVA与XML之间来回切换
??spring-test:对JUNIT等测试框架的简单封装
??spring-tx:为JDBC、Hibernate、JDO、JPA等提供的一致的声明式和编程式事务管理。
??spring-web:包含Web应用开发时,用到Spring框架时所需的核心类,包括自动载入WebApplicationContext特性的类、Struts与JSF集成类、文件上传的支持类、Filter类和大量工具辅助类。
??spring-webmvc:包含SpringMVC框架相关的所有类。包含国际化、标签、Theme、视图展现的FreeMarker、JasperReports、 Tiles、Velocity、XSLT相关类。当然,如果你的应用使用了独立的MVC框架,则无需这个JAR文件里的任何类。
??spring-webmvc-portlet:Spring MVC的增强
??spring-websocket:提供 Socket通信, web端的推送功能

Spring的IOC配置

导入IOC相关jar包

spring-beans-4.3.24.RELEASE.jar
spring-context-4.3.24.RELEASE.jar
spring-context-support-4.3.24.RELEASE.jar
spring-core-4.3.24.RELEASE.jar
spring-expression-4.3.24.RELEASE.jar

日志包

commons-logging-1.2.jar
log4j-1.2.17.jar
log4j-api-2.11.2.jar
log4j-core-2.11.2.jar

Spring配置文件:

<?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="user"  class="com.sxt.bean.User" />
</beans>

测试程序

package com.sxt.test;

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

import com.sxt.bean.User;

public class Test {
	
	public static void main(String[] args) {
		// 引入配置文件 读取配置信息
		ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
		//new User()
		// 此时使用 spring 容器 : 根据指定的类,就可以获取这个类的对象
		// 说明容器中,本身就存在这个对象,那么一定有人创建了对象,创建人不是程序员,是Spring
		// 此时  创建对象的权利,从开发者的手中,移交到Spring框架.这就是IOC (控制反转)
		// 创建对象,控制对象的生命周期的角色发生反转,所以被称之为控制反转
		// 从Spring IOC容器中获取对象
		User bean = context.getBean(User.class);
		// 使用对象调用方法
		bean.study();
		System.out.println(bean);
		User bean2 = context.getBean(User.class);
		System.out.println(bean2);
	}

}

Spring创建对象的三种方式

方式一:构造方法

???使用构造器创建Bean对象,必须要有无参构造方法

<!-- 
	id : bean标签唯一标识 也是对象唯一标识   一个bean只有一个ID值且整个IOC容器ID值不允许重复
	name : bean标签中name属性,也是对象的name值,name值可以多个,使用逗号分隔.当name值没有时,id值就是name值
	class : 需要创建对象的类
 -->
<bean id="user" name="user1,user2,user3"  class="com.sxt.bean.User" />

方式二:静态工厂

<!-- 
    方式二: 使用静态工厂方式
	class : 工厂类
	factory-method : 工厂方法
 -->
<bean  id="userFactory"  class="com.sxt.factory.UserFactory"  factory-method="getUser"></bean>
package com.sxt.factory;

import com.sxt.bean.User;

public class UserFactory {	
	
	public static User getUser() {
		return new User();
	}

}

方式三:非静态工厂

<!-- 
    方式三: 非静态工厂
	factory-bean : 工厂对象
	factory-method : 工厂方法
-->
<!-- 创建工厂对象,用于调用工厂中非静态的方法 -->
<bean id="userDyFactory"  class="com.sxt.factory.UserDyFactory"></bean>
<!-- 根据工厂对象,工厂方法创建Bean对象 -->
<bean  id="userBean" factory-bean="userDyFactory"  factory-method="getUser"></bean>
package com.sxt.factory;

import com.sxt.bean.User;

public class UserDyFactory {
	
	/**
	 * 非静态方法
	 */
	public  User getUser() {
		return new User();
	}
}

Spring的属性注入

构造方法注入

<?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="user1" class="com.sxt.bean.User"></bean>
	<!-- 创建对象: 2个参数的构造方法 -->
	<bean id="user2" class="com.sxt.bean.User">
		<constructor-arg index="0"  value="韩梅梅"></constructor-arg>
		<constructor-arg index="1" value="女"></constructor-arg>
	</bean>
	<!-- 创建对象: 3个参数的构造方法 -->
	<bean id="user3" class="com.sxt.bean.User">
		<constructor-arg index="0"  value="韩梅梅"></constructor-arg>
		<constructor-arg index="1" value="女"></constructor-arg>
		<constructor-arg index="2" value="18"></constructor-arg>
	</bean>
	<!-- 创建对象: 构造方法  参数名称注入属性值 -->
	<bean id="user4" class="com.sxt.bean.User">
		<constructor-arg name="name"  value="韩梅梅"></constructor-arg>
		<constructor-arg name="sex"  value="女"></constructor-arg>
		<constructor-arg name="age"  value="18"></constructor-arg>
	</bean>
	
</beans>
package com.sxt.bean;

public class User {
	
//	private String name;
//	private String sex;
//	private Integer age;
	
	private String name1;
	private String sex1;
	private Integer age1;
		
	public User() {
		System.out.println("我是无参构造方法");
	}
		
	public User(String name, String sex) {
		this.name1 = name;
		this.sex1 = sex;
	}

	public User(String name, String sex, Integer age) {
		this.name1 = name;
		this.sex1 = sex;
		this.age1 = age;
	}
	
	public void study() {
		System.out.println("我是学习方法");
	} 
    
	public String getName() {
		return name1;
	}
	public void setName(String name) {
		this.name1 = name;
	}    
	public String getSex() {
		return sex1;
	}
	public void setSex(String sex) {
		this.sex1 = sex;
	}
	public Integer getAge() {
		return age1;
	}
	public void setAge(Integer age) {
		this.age1 = age;
	}

	@Override
	public String toString() {
		return "User [name=" + name1 + ", sex=" + sex1 + ", age=" + age1 + "]";
	}

}

使用set方法注入属性值

<!-- 
	方式二: 使用set方法注入属性
		此时的name 值 不是真的类中属性名  只 set方法中setXxx中xxx
-->
<bean id="user5"  class="com.sxt.bean.User">
	<property name="name"  value="韩梅梅"></property>
	<property name="sex"  value="女"></property>
	<property name="age"  value="18"></property>
</bean>
package com.sxt.bean;

public class User {	
	private String name1;
	private String sex1;
	private Integer age1;
	
	public User() {
		System.out.println("我是无参构造方法");
	}
	
	public User(String name, String sex) {
		this.name1 = name;
		this.sex1 = sex;
	}

	public User(String name, String sex, Integer age) {
		this.name1 = name;
		this.sex1 = sex;
		this.age1 = age;
	}
	
	public void study() {
		System.out.println("我是学习方法");
	}

	public String getName() {
		return name1;
	}
	public void setName(String name) {
		this.name1 = name;
	}
	public String getSex() {
		return sex1;
	}
	public void setSex(String sex) {
		this.sex1 = sex;
	}
	public Integer getAge() {
		return age1;
	}
	public void setAge(Integer age) {
		this.age1 = age;
	}

	@Override
	public String toString() {
		return "User [name=" + name1 + ", sex=" + sex1 + ", age=" + age1 + "]";
	}

}

各种类型的属性注入

<?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. 注入字符串 -->
	 <bean id="user1" class="com.sxt.bean.User">
	 	<property name="str"  value="我是字符串"></property>
	 </bean>
	 <!-- 2. 注入对象 方式一 -->
	 <bean id="st1" class="com.sxt.bean.Student">
	  	<property name="name" value="韩梅梅"> </property>
	  	<property name="sex" value="女"> </property>
	 </bean>
	  <!-- 
		在注入属性值时,value 只能注入:基本数据类型和字符串,如果是对象,需要使用  ref 进行对相关联
	   -->
	 <bean id="user2" class="com.sxt.bean.User">
	  	<property name="st" ref="st1" >
	  	</property>
	 </bean>
	  <!-- 注入对象方式二  -->
	 <bean id="user3" class="com.sxt.bean.User">
	  	<property name="st">
	  		<bean class="com.sxt.bean.Student">
	  			<property name="name" value="韩梅梅"> </property>
	  			<property name="sex" value="女"> </property>
	  		</bean>
	  	</property>
	  </bean>
	 <!--3 .注入数组结构  -->
	 <bean id="user4" class="com.sxt.bean.User">
	 	<property name="list1">
	 		<array>
	 			<value>韩梅梅</value>
	 			<value>李磊</value>
	 			<value>Jim</value>
	 			<value>Lucy</value>
	 		</array>
	 	</property>
	 </bean>
	 <!--  list结构属性  -->
	 <bean id="user5" class="com.sxt.bean.User">
	 	<property name="list1">
	 		<list>
				<value>韩梅梅</value>
	 			<value>李磊</value>
	 			<value>Jim</value>
	 			<value>Lucy</value>		
	 		</list>
	 	</property>
	 </bean>
	  <bean id="user6" class="com.sxt.bean.User">
	 	<property name="list2">
	 		<list>
				<bean class="com.sxt.bean.Student">
					<property name="name" value="韩梅梅"></property>
					<property name="sex" value="女"></property>
				</bean>	
				<bean class="com.sxt.bean.Student">
					<property name="name" value="Lucy"></property>
					<property name="sex" value="女"></property>
				</bean>
				<ref bean="st1"/>	
	 		</list>
	 	</property>
	 </bean>
	 <!-- set结构属性 -->
	 <bean id="user7" class="com.sxt.bean.User">
	 	<property name="set1">
	 		<set>
	 			<value>字符串1</value>
	 			<value>字符串2</value>
	 			<value>字符串3</value>
	 			<value>字符串1</value>
	 			<value>字符串1</value>
	 		</set>
	 	</property>
	 </bean>
	 
	 <bean id="user8" class="com.sxt.bean.User">
	 	<property name="set2">
	 		<set>
	 			<bean class="com.sxt.bean.Student">
					<property name="name" value="韩梅梅"></property>
					<property name="sex" value="女"></property>
				</bean>	
				<bean class="com.sxt.bean.Student">
					<property name="name" value="Lucy"></property>
					<property name="sex" value="女"></property>
				</bean>
				<ref bean="st1"/>	
	 		</set>
	 	</property>
	 </bean>
	 <!-- map结构  -->
	 <bean id="user9" class="com.sxt.bean.User">
	 	<property name="map1">
	 		<map>
	 			<entry key="key1" value="value1"></entry>
	 			<entry key="key2" value="value2"></entry>
	 			<entry key="key3" value="value3"></entry>
	 			<entry key="key4" value="value4"></entry>
	 		</map>
	 	</property>
	 </bean>
	 
	 <bean id="user10" class="com.sxt.bean.User">
	 	<property name="map2">
	 		<map>
	 			<entry key="key1"  value-ref="st1"></entry>
	 			<entry key="key2"  >
	 				<bean class="com.sxt.bean.Student">
	 					<property name="name" value="韩梅梅"></property>
						<property name="sex" value="女"></property>
	 				</bean>
	 			</entry>
	 		</map>
	 	</property>
	 </bean>
	 <!-- properties 对象 -->
	 <bean id="user11" class="com.sxt.bean.User">
	 	<property name="prop">
	 		<props>
	 			<prop key="key1">value1</prop>
	 			<prop key="key2">value2</prop>
	 			<prop key="key3">value3</prop>
	 		</props>	
	 	</property>
	 </bean>
</beans>
package com.sxt.bean;

import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

public class User {

	private String str;		// 字符串
	private Student st;		// 对象
	
	private List<String> list1;		//list集合
	private List<Student> list2;	//list集合
	
	private Set<String> set1;	//set集合
	private Set<Student> set2;	//set集合
	
	private Map<String,String> map1;	// Map	
	private Map<String,Student> map2;	// Map
	
	private Properties prop;	// properties

	public String getStr() {
		return str;
	}
	public void setStr(String str) {
		this.str = str;
	}
	public Student getSt() {
		return st;
	}
	public void setSt(Student st) {
		this.st = st;
	}
	public List<String> getList1() {
		return list1;
	}
	public void setList1(List<String> list1) {
		this.list1 = list1;
	}
	public List<Student> getList2() {
		return list2;
	}
	public void setList2(List<Student> list2) {
		this.list2 = list2;
	}
	public Set<String> getSet1() {
		return set1;
	}
	public void setSet1(Set<String> set1) {
		this.set1 = set1;
	}
	public Set<Student> getSet2() {
		return set2;
	}
	public void setSet2(Set<Student> set2) {
		this.set2 = set2;
	}
	public Map<String, String> getMap1() {
		return map1;
	}
	public void setMap1(Map<String, String> map1) {
		this.map1 = map1;
	}
	public Map<String, Student> getMap2() {
		return map2;
	}
	public void setMap2(Map<String, Student> map2) {
		this.map2 = map2;
	}
	public Properties getProp() {
		return prop;
	}
	public void setProp(Properties prop) {
		this.prop = prop;
	}

}

spring属性介绍

<?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">
	<!-- 
		注意: 
			在spring中,默认会根据配置文件创建对象放入到ioc容器中
				lazy-init : 是否懒加载   default/false  : 不进行懒加载 ,程序启动加载对象.true 进行懒加载,只有使用时才加载
				scope :  对象作用域
						singleton : 单例   默认
						prototype : 非单例 
						request   : 每次请求创建对象    
						session	  : 每次会话	
				init-method :	
						初始化方法  对象创建后进行对象初始化调用的方法
				destroy-method :
						ioc容器中,对象销毁时调用的方法		
				autowire :自动装配对象属性
						byType : 根据类型装配
						byName : 根据属性的name装配
				
				autowire-candidate : 是否被自动装配查找
					true : 可以被自动装配   默认
					false : 不可以被自动装配
				primary :
					在装配时,推荐使用的
				abstract : 是否是抽象类
				
				parent : 父级,可以进行属性继承	
				
				depends-on : 依赖的Bean						
	 -->
	 
	 <bean id="user1" class="com.sxt.bean.User"  scope="singleton" init-method="init"  destroy-method="destory"  depends-on="st" ></bean>
	 
	 <bean id="st" class="com.sxt.bean.Student" autowire-candidate="default" >
	 	<property name="name"  value="韩梅梅"></property>
	 	<property name="sex"  value="18"></property>
	 </bean>	 
</beans>

spring改造web3层结构

pojo

package com.sxt.pojo;

public class User {
	
	private String name;
	private Integer age;
	
	public User() {}
	public User(String name, Integer age) {
		this.name = name;
		this.age = age;
	}
    
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return "User [name=" + name + ", age=" + age + "]";
	}
}

dao

package com.sxt.dao;

import java.util.List;

import com.sxt.pojo.User;

public interface IUserDao {
	public List<User> selectAll();
}

dao.impl

package com.sxt.dao.impl;

import java.util.ArrayList;
import java.util.List;

import com.sxt.dao.IUserDao;
import com.sxt.pojo.User;

public class UserDaoImpl  implements IUserDao{

	@Override
	public List<User> selectAll() {
		System.out.println("dao 层  selectAll");
		List<User> list = new ArrayList<User>();
		list.add(new User("韩梅梅", 18));
		list.add(new User("Lucy", 18));
		list.add(new User("Lily", 18));
		return list;
	}

}

service

package com.sxt.service;

import java.util.List;

import com.sxt.pojo.User;

public interface IUserService {

	public List<User> queryAll();
}

service.impl

package com.sxt.service.impl;

import java.util.List;

import com.sxt.dao.IUserDao;
import com.sxt.pojo.User;
import com.sxt.service.IUserService;

public class UserServiceImpl implements IUserService {
	
	private IUserDao userDao;

	@Override
	public List<User> queryAll() {
		return userDao.selectAll();
	}

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

controller

package com.sxt.controller;

import java.util.List;

import com.sxt.pojo.User;
import com.sxt.service.IUserService;

public class UserController {
	
	private IUserService userService;
	
	public void list() {
		List<User> users = userService.queryAll();
		for (User user : users) {
			System.out.println(user);
		}
	}

	public void setUserService(IUserService userService) {
		this.userService = userService;
	}
}

配置文件:

<?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">
	<!-- 配置Dao 层 -->
	<bean id="userDao" class="com.sxt.dao.impl.UserDaoImpl"></bean>
	
	<!-- 配置Service -->
	<bean id="userService" class="com.sxt.service.impl.UserServiceImpl">
		<property name="userDao" ref="userDao"></property>
	</bean>
	<!-- 配置controller -->
	<bean id="userController" class="com.sxt.controller.UserController">
		<property name="userService" ref="userService"></property>
	</bean> 
</beans>

测试类:

package com.sxt.test;

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

import com.sxt.controller.UserController;

public class Test {
	public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
		UserController bean = context.getBean(UserController.class);	
		bean.list();	
	}
}

IOC相关注解

? 为了简化开发,Spring提供了一些内置注解:

? @Component:表示是一个组件,使用该注解修饰类,Spring自动为其创建对象,放入IOC容器

? @Service:继承于Component 注解,表示一个组件,主要用于Service层

? @Repository:继承于Component 注解,表示一个组件,主要用持久层

? @Controller:继承于Component 注解,表示一个组件,主要用于控制层

? @Autowired:用于为属性进行自动装配

? **@Qualifier(name)**:组件名称

导入jar包

spring-aop-4.3.24.RELEASE.jar

引入xml约束

aop约束
context约束

配置组件扫描

<?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/context https://www.springframework.org/schema/context/spring-context.xsd
		http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
	<!-- 扫描注解组件,使其生效 -->
	<context:component-scan base-package="com.sxt.dao.impl,com.sxt.service.impl,com.sxt.controller"></context:component-scan>
	<!-- 包下面所有的类都要进行扫描 -->
	<!-- <context:component-scan base-package="com.sxt"></context:component-scan> -->
</beans>

AOP

AOP的概念

???Spring的IoC是管理对象,使用AOP管理方法。如何管理方法,扩展方法,如何扩展方法?方法中套方法,装饰者模式。

???但是装饰者模式,需要类与类之间存在关系.提高了程序耦合读,不便于维护和扩展.基于这个原因,开发者提出了AOP的想法,面向切面编程 ----- 横向扩展程序.这种扩展方式,也被称之为拔插式的扩展,需要使用时,只需要织入想要扩展的内容,不需要时,只需要取消织入. 具体的实现,依赖动态代理模式,相对于纵向扩展,编码的复杂度高一些,但是代码灵活一些。

技术图片

场景

  1. 事务管理

??开启事务

??关闭事务

??回滚事务

  1. 日志采集

??将请求信息进行持久化.发生请求信息获得方式都一样,只需要将请求对象统一保存.数据分析.

JDK代理

???代理,代替打理。

静态代理

package com.sxt.target;
/**
 * 被代替的类
 */
public class TargetClass {
	
	public void sing() {
		System.out.println("   世上只有妈妈好   ");
	}
}
package com.sxt.target;
/**
 * 代理类
 */
public class ProxyClass {
	// 被代理的对象
	TargetClass targetClass;
	public ProxyClass(TargetClass targetClass) {
		super();
		this.targetClass = targetClass;
	}
	public void sing() {
		System.out.println("查看行程计划");
		System.out.println("确定时间");
		System.out.println("修改行程计划");
		System.out.println("下周二");
		targetClass.sing();
	}
}
package com.sxt.target;

public class Test {
	public static void main(String[] args) {
		// 被代理的对象
		TargetClass targetClass = new  TargetClass();
		// 创建代理类
		ProxyClass proxyClass = new ProxyClass(targetClass);
		//调用方法
		proxyClass.sing();
	}

}

静态代理的不足:

???必须定义代理类,且代理的方法声明了,扩展性相对较差.类和类之间产生了关系,耦合性加强了.不便于维护 ,代码的可读性也会降低。

动态代理

??动态的为需要代理的类,创建一个具体的代理类.不再需要开发者定义具体的代理的类.这种方式,就是动态代理.JDK为此制定了一个标准.

类: Proxy代理类,所有代理的类基类

???Proxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类.

??newProxyInstance(ClassLoader loader, Class<?>... interfaces,InvocationHandler hanlder) : 类加载器 当前类的加载器,interfaces 接口的Class对象 hanlder 代理类的处理器

??接口:InvocationHandler 与代理类关联调用程序的处理器

配置类:
package com.sxt.target;
/**
 * 配置类
 */
public class Config {
	
	//开启事务的方法的名称的前缀
	public static String[] preFix =  {"add","update","delete"};

}
代理类处理器
package com.sxt.target;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * 代理类绑定的代理处理器
 */
public class ProxyHanlder implements InvocationHandler {
	
	// 被代理的目标  此时类型时  Object  那么传入任何类型都可以
	private Object proxyTarget;
	
	public ProxyHanlder(Object proxyTarget) {
		this.proxyTarget = proxyTarget;
	}

	/**
	 * 	proxy : ProxyHanlder 对象  代理处理器对象
	 * 	method : 被代理调用的方法
	 * 	args : 方法中参数
	 */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		
		String methodName = method.getName();
		for (String  name : Config.preFix) {
			if(methodName.startsWith(name)) {
				new TransctionManager().beginTrancation();
			}
		}
		Object obj = method.invoke(proxyTarget, args);
		for (String  name : Config.preFix) {
			if(methodName.startsWith(name)) {
				new TransctionManager().commitTrancation();
			}
		}
		
		return obj;
	}

}
被代理目标类:
package com.sxt.target;
/**
 * @ClassName: TargetClassInteterface 
 * @Description: 被代理的类的接口   
 * @author: Mr.T
 * @date: 2019年11月22日 上午11:14:03
 */
public interface TargetClassInteterface {
	
	public void  addUser(String name) ;
	public void  deleteUser() ;	
	public void  updateUser() ;	
	public void  selectUser() ;

}

package com.sxt.target;
/**
 * @ClassName: TargetClass 
 * @Description: 具体的代理类
 * @author: Mr.T
 * @date: 2019年11月22日 上午11:15:19
 */
public class TargetClass implements TargetClassInteterface {

	@Override
	public void addUser(String name) {
		System.out.println("新增用户");		
	}

	@Override
	public void deleteUser() {
		System.out.println("删除用户");
	}

	@Override
	public void updateUser() {
		System.out.println("修改用户");
	}

	@Override
	public void selectUser() {
		System.out.println("查询用户");
		
	}

}
增强的内容:
package com.sxt.target;
/**
 * @ClassName: TransctionManager 
 * @Description: 事务管理器  增强的具体内容
 * @author: Mr.T
 * @date: 2019年11月22日 上午11:35:37
 */
public class TransctionManager {
	public void beginTrancation() {
		System.out.println("开启事务");
	}	
	
	public void commitTrancation() {
		System.out.println("提交事务");
	}
}
测试类:
package com.sxt.target;

import java.lang.reflect.Proxy;

public class Test {
	
	public static void main(String[] args) {
        // 生成代理编译后的文件
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
		// 创建了被代理的目标
		TargetClassInteterface targetInterface = new TargetClass();
		// 创建代理类的处理器
		ProxyHanlder proxyHandler = new ProxyHanlder(targetInterface);
		// 创建代理类
		TargetClassInteterface proxyObj = (TargetClassInteterface) Proxy.newProxyInstance(Test.class.getClassLoader(), new Class[] {TargetClassInteterface.class}, proxyHandler);
		proxyObj.addUser("user");
		System.out.println("======================");
		proxyObj.deleteUser();
		System.out.println("======================");
		proxyObj.updateUser();
		System.out.println("======================");
		proxyObj.selectUser();
		System.out.println("======================");
	}

}

不足:

  1. 必须依赖接口,具有一定局限性。
  2. 由于使用的反射,所以效率相对较低。
源码分析
package com.sun.proxy;

import com.sxt.target2.TargetClassInteterface;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
// 生成的代理类  $Proxy0 是 Proxy 子类且是 TargetClassInteterface 实现类  
// 那么这个代理类就要有  TargetClassInteterface 里面抽象方法
public final class $Proxy0   extends Proxy   implements TargetClassInteterface   {
	
	private static Method m0;   // ======> Object类中的 hashCode
	private static Method m1;   // ======> Object类中的 equals
	private static Method m2;   // ======> Object类中的 toString 
	private static Method m3;   // ======> 实现了接口中 addUser 方法
	
static
  {
    try {
	  m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
	  m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      m3 = Class.forName("com.sxt.target2.TargetClassInteterface").getMethod("addUser", new Class[] { Class.forName("java.lang.String") });
      return;
    }
    catch (NoSuchMethodException localNoSuchMethodException) {
      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    }
    catch (ClassNotFoundException localClassNotFoundException) {
      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
    }
  }	
  // 创建代理类对象 InvocationHandler 对象  本质上就是传入 ProxyHanlder  自己定义的代理类程序处理器
  
  public $Proxy0(InvocationHandler paramInvocationHandler)
    throws 
  {
	// 调用父类的有参构造方法 : 将自己定义 ProxyHanlder 传给Proxy
    super(paramInvocationHandler);
	// 将自己定义的处理器  赋值给了  Proxy 类中  h 成员变量     
  }
  
  public final boolean equals(Object paramObject)
    throws 
  {
    try
    {
      return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  // 在测试类中,使用创建出来的代理对象   调用  addUser  ,其实就是调用此处的addUser
  public final void addUser(String paramString)
    throws 
  {
    try
    {
	  // this.h : ProxyHandler对象	
	  // this.h 当前类中h变量  当前类中没有 h  所以h是从父类  Proxy类继承而来.
	  // this.h 就是父类Proxy中h,而Proxy中h ,是自定义的ProxyHandler
	  // proxyHandler.invoke(this,m3,paramString); //this : proxy 代理类对象   m3 具体的add方法   paramString 传入的参数
	  // 调用Proxy Handler的 invoke 方法
	  /*
			// 被代理的目标  此时类型时  Object  那么传入任何类型都可以
		private Object proxyTarget;
		
		public ProxyHanlder(Object proxyTarget) {
			this.proxyTarget = proxyTarget;
		}
	  
	  	@Override
		public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
			beginTrancation();  // 开启事务 
			//m3 addUser.invoke(obj ,args ) : // 此时的obj :proxyTarget  ----> 被代理的具体目标类对象    addUser(String name) { 新增用户 }
			Object obj = method.invoke(proxyTarget, args);
			commitTrancation();
			return obj;
		}	  
	  */
	  	  
      this.h.invoke(this, m3, new Object[] { paramString });
      return;
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final String toString()
    throws 
  {
    try
    {
      return (String)this.h.invoke(this, m2, null);
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final int hashCode()
    throws 
  {
    try
    {
      return ((Integer)this.h.invoke(this, m0, null)).intValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
}

JDK动态代理的不足:

??结构相对复杂,必须依赖接口.被代理的对象要有接口(接口要当做参数传递).其二,其本质是使用的反射,执行效率相对而言较低.

由于以上原因,Cglib出现,解决以上问题.

Cglib动态代理

??问题1:必须要有接口,没有接口如何实现动态代理?

?????既然没有接口,那么使用子类,使用继承。

???问题2:利用反射执行效率低,如何解决效率低?

????执行效率低,创建对象,低在方法查找。那么将需要代理的方法创建好,存储在容器中,需要使用时,根据方法对应的索引,找到方法.。

Cglib使用

  1. 导入jar包

    asm-7.0.jar
    cglib-3.2.10.jar
    
  2. 编写代码

目标类

package com.target;
/**
 * 被代理的类
 */
public class TargetClass {
		
	public void  sing() {
		System.out.println("唱歌");
	}

}

增强类

package com.target;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
 * 方法拦截器
 */
public class MyMethodIntercepter implements  MethodInterceptor {

	@Override
	public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
		before();
		// obj : 子类对象    ----父类  TargetClass
		// args : 参数
		// cglib的动态代理 不是反射. 使用 索引找到该方法
		Object rs = proxy.invokeSuper(obj, args);
		after();
		return rs;
	}

	public void before() {
		System.out.println("前置增强");
	}
		
	public void after() {
		System.out.println("后置增强");
	}
}

创建代理类:

package com.target;

import net.sf.cglib.core.DebuggingClassWriter;
import net.sf.cglib.proxy.Enhancer;

public class Test {
	
	public static void main(String[] args) {
		System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D://java");
		// 创建增强器
		Enhancer enhancer = new Enhancer();
		// 增强的目标
		enhancer.setSuperclass(TargetClass.class);
		// 使用谁增强
		enhancer.setCallback(new MyMethodIntercepter());
		// 创建代理类
		TargetClass obj = (TargetClass) enhancer.create();
		// 调用方法
		obj.sing();
	}
}
package com.target;

import java.lang.reflect.InvocationTargetException;

import net.sf.cglib.core.DebuggingClassWriter;
import net.sf.cglib.reflect.FastClass;

public class Test2 {
	
	public static void main(String[] args) {
		System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D://java");
		FastClass create = FastClass.create(TargetClass.class);
		//获取方法的索引
		int index = create.getIndex("sing", new Class[] {});
		//调用方法
		try {
			create.invoke(index, new TargetClass(), null);
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
	}
}

Cglib动态代理的不足

  1. 由于Cglib使用继承,所以无法代理final修饰类
  2. 也无法代理final修饰的方法

spring-Aop 配置方式一

  1. 导入jar包

    aspectjweaver.jar
    commons-logging-1.2.jar
    log4j-1.2.17.jar
    log4j-api-2.11.2.jar
    log4j-core-2.11.2.jar
    spring-aspects-4.3.24.RELEASE.jar
    spring-beans-4.3.24.RELEASE.jar
    spring-context-4.3.24.RELEASE.jar
    spring-context-support-4.3.24.RELEASE.jar
    spring-core-4.3.24.RELEASE.jar
    spring-expression-4.3.24.RELEASE.jar
    
  2. 编写代码

被增强的目标

   package com.sxt.target;
   /**
    * 目标类接口
    */
   public interface ITargetClass {
   
   	/**
   	 * 唱歌方法
   	 */
   	public void  sing();
   }
   
   package com.sxt.target.impl;
   
   import com.sxt.target.ITargetClass;
   
   public class TargetClassImpl implements  ITargetClass{
   
   	@Override
   	public void sing() {
   		int m = 0;
   		System.out.println(1/m);
   		System.out.println(" 月亮代表我的心 ");
   	}
   
   }

增强类:

package com.sxt.advice;

import java.lang.reflect.Method;

import org.springframework.aop.MethodBeforeAdvice;

public class BeforeAdvice implements MethodBeforeAdvice {
    
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("前置增强");
    }
    
}
package com.sxt.advice;
   
import java.lang.reflect.Method;
   
import org.springframework.aop.AfterReturningAdvice;
/**
 * 后置增强类
 */
public class AfterAdvice  implements AfterReturningAdvice{
   
   	@Override
   	public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
   		System.out.println("后置增强");
   	}
   
}
package com.sxt.advice;
   
import java.lang.reflect.Method;
   
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
   
/**
 * 环绕增强
 */
public class RoundAdvice implements MethodInterceptor {
   
   	@Override
   	public Object invoke(MethodInvocation invocation) throws Throwable {
   		//调用前置增强
   		beforeAdvice();
   		//目标方法执行
   		Method method = invocation.getMethod();	//目标方法
   		Object[] arguments = invocation.getArguments();	//目标方法的参数
   		//执行当前目标方法
   		Object rs = invocation.proceed();
   		afterAdvice();
   		return rs;
   	}
   	
   	public void  beforeAdvice() {
   		System.out.println("前置增强");
   	}
   	
   	public void  afterAdvice() {
   		System.out.println("后置增强");
   	}
}
package com.sxt.advice;
   
import org.springframework.aop.ThrowsAdvice;
   
public class ExceptionAdvice  implements ThrowsAdvice{
   	
/**
 * 方法名必须为afterThrowing 且要有 Throwable 参数 
 */
   	public void afterThrowing(Throwable th) {
   		System.out.println("我是异常增强,发生异常时我执行");
   	}
   
}  

aop配置

<?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"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
   		http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
   		http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
	<!-- 配置增强的目标 -->
	<bean id="targetClass" class="com.sxt.target.impl.TargetClassImpl"></bean>
	<!-- 具体增强类对象 -->
	<!-- 前置增强 -->
	<bean id="beforeAdvice" class="com.sxt.advice.BeforeAdvice"></bean>
	<!-- 后置增强 -->
	<bean id="afterAdvice" class="com.sxt.advice.AfterAdvice"></bean>
	<!-- 环绕增强 -->
	<bean id="roundAdvice" class="com.sxt.advice.RoundAdvice"></bean>
	<!-- 异常增强 -->
	<bean id="exceptionAdvice" class="com.sxt.advice.ExceptionAdvice"></bean>
    
	<!-- 织入: 将切点 和 具体增强类结合 -->
	<!-- 进行AOP配置 -->
	<aop:config>
		<!-- 配置切入点 : 需要增强的方法 -->
		<aop:pointcut expression="execution(* com.sxt.target.impl.TargetClassImpl.*(..))" id="pointcut" />
		<!-- 配置切面方法 -->
		<!-- <aop:advisor advice-ref="beforeAdvice" pointcut-ref="pointcut"/> -->
		<!-- <aop:advisor advice-ref="afterAdvice" pointcut-ref="pointcut"/> -->
		<!-- <aop:advisor advice-ref="roundAdvice" pointcut-ref="pointcut"/> -->
		<aop:advisor advice-ref="exceptionAdvice" pointcut-ref="pointcut" />
	</aop:config>
    
</beans>

测试:

package com.sxt.test;
   
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
   
import com.sxt.target.ITargetClass;
   
public class Test {
   	
	public static void main(String[] args) {
   		ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
   		ITargetClass obj = (ITargetClass) context.getBean("targetClass");
   		obj.sing();
   	}
}

Spring-Aop 配置方式二

? AspectJ是一个基于Java语言的AOP框架,Spring2.0开始引入对AspectJ的支持,AspectJ扩展了Java语言,提供了专门的编译器,在编译时提供了横向代码的注入。

? @AspectJ是AspectJ1.5新增功能,通过JDK1.5注解技术,允许直接在Bean中定义切面

? 新版本的Spring中,建议使用AspectJ方式开发AOP

编写目标类:

package com.sxt.target;
   /**
    * 目标类接口
    */
public interface ITargetClass {
   
   	/**
   	 * 唱歌方法
   	 */
	public void  sing();
}
package com.sxt.target.impl;

import com.sxt.exception.MyException;
import com.sxt.target.ITargetClass;

public class TargetClassImpl implements ITargetClass{

	@Override
	public void sing() {
		throw new MyException("4001001", "自己定义的异常");
		// System.out.println("");
	}

}

增强类:

package com.sxt.advice;

import org.aspectj.lang.ProceedingJoinPoint;

import com.sxt.exception.MyException;

/**
 * 增强类
 */
public class MyAdvice {

	public void beforeAdvice() {
		System.out.println("前置增强");
	}

	public void afterAdvice() {
		System.out.println("后置增强");
	}

	public void roundAdvice(ProceedingJoinPoint pjp) {
		beforeAdvice();
		// 获取参数
		Object[] args = pjp.getArgs();
		// 增强的目标方法
		Object target = pjp.getTarget();
		try {
			Object proceed = pjp.proceed();
			afterAdvice();
		} catch (Throwable e) {
			e.printStackTrace();
		}
	}

	/**
	 * 可以做异常拦截
	 */
	public void exceptionAdvice(Throwable tx) {
		if (tx instanceof MyException) {
			MyException myException = (MyException) tx;
			System.out.println(myException.getCode());
			System.out.println(myException.getMsg());
			return;
		}
		System.out.println(tx);
		System.out.println("异常增强");
	}
}

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"
   	xmlns:aop="http://www.springframework.org/schema/aop"
   	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
   		http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
   		http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
   	<!-- 配置增强的目标 -->
   	<bean id="targetClass" class="com.sxt.target.impl.TargetClassImpl"></bean>
   	<!-- 具体增强类对象  -->
   	<bean id="myAdvice" class="com.sxt.advice.MyAdvice"></bean>
   	<!-- 
   		织入: 将切点 和  具体增强类结合  
   	 -->
   	 <!-- 进行AOP配置 -->
   	<aop:config>
   		<!--  配置增强对象 -->
   		<aop:aspect ref="myAdvice">
   			<!-- 配置切入点 -->
   			<aop:pointcut expression="execution(* com.sxt.target.impl.*.*(..))" id="pointcut"/>
   			<!-- 配置增强对象中方法  前置增强  -->
   		<!-- 	<aop:before method="beforeAdvice" pointcut-ref="pointcut" /> -->
   		<!-- 后置增强 -->
   		<!-- 	<aop:after method="afterAdvice" pointcut-ref="pointcut"/> -->
   		<!-- 环绕增强  -->
   		<!-- <aop:around method="roundAdvice" pointcut-ref="pointcut"/> -->
   		<!-- 异常增强 -->
   		<aop:after-throwing method="exceptionAdvice" pointcut-ref="pointcut" throwing="tx"/>
   		</aop:aspect>
   	</aop:config>
</beans> 

Spring-Aop 配置方式:注解

增强类:

package com.sxt.advice;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
import com.sxt.exception.MyException;

/**
 * 增强类
 */
@Component
@Aspect
public class MyAdvice {
	
	// @Before("execution(* com.sxt.target.impl.*.*(..))")
	public void beforeAdvice() {
		System.out.println(this);
		System.out.println("前置增强");
	}
	/**
	 * @AfterReturning 可以拿到  目标方法的返回值
	 * @After 只能后置增强的效果
	 */
	@AfterReturning(value="execution(* com.sxt.target.impl.*.*(..))",returning = "rs")
	public void afterAdvice(Object rs) {
		System.out.println(rs);
		System.out.println("后置增强");
	}
	
    // execution(* 包名.类.方法(..)   	..:表示任意参数
	// @Around("execution(* com.sxt.target.impl.*.*(..))")
	public void roundAdvice(ProceedingJoinPoint pjp) {
		beforeAdvice();
		// 获取参数
		Object[] args = pjp.getArgs();
		// 增强的目标方法
		Object target = pjp.getTarget();
		try {
			Object proceed = pjp.proceed();
			
			//afterAdvice();
		} catch (Throwable e) {
			e.printStackTrace();
		}
	}
	/**
	 * 可以做异常拦截
	 */
	// @AfterThrowing( value="execution(* com.sxt.target.impl.*.*(..))",throwing = "tx")
	public void exceptionAdvice(Throwable tx) {
		if(tx instanceof MyException) {
			MyException myException = (MyException) tx;
			System.out.println(myException.getCode());
			System.out.println(myException.getMsg());
			return ;
		}
		System.out.println(tx);
		System.out.println("异常增强");
	} 
}

目标类:

package com.sxt.target.impl;

import org.springframework.stereotype.Component;

import com.sxt.exception.MyException;
import com.sxt.target.IUserDao;

@Component
public class UserDaoImpl implements IUserDao {
	@Override
	public int sing() {
		//throw new MyException("4001001", "自己定义的异常");
		System.out.println(" 月亮代表我的心 ");
		return 10;
	}
}

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"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
		http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
	
	<!-- 扫描组件 -->
	<context:component-scan base-package="com.sxt"></context:component-scan>
	<!-- 开启注解式 增强的通知
		proxy-target-class  使用cglib 创建代理对象
		1. UserDao 创建代理对象
		2. 增强类绑定
		 	默认是JDK 的代理动态代理  ===  UserDaoImpl 代理类
	 -->
	<aop:aspectj-autoproxy  proxy-target-class="true"  ></aop:aspectj-autoproxy>
</beans> 

总结

IoC/DI和AOP

IoC : 控制反转

??对于整个应用而言,创建对象的权利,从应用自身创建移交给了Spring容器.对象的创建的权利发生转向.所以被称之为控制反转.

DI : 依赖注入

??在研究控制反转时,发现其实反转的内容主要只,对象创建和对象注入.且对象的创建存在依赖关系.所以,控制反转其实更具体就是注入对象.所以被称之为DI.

??控制反转和依赖注入本质上一样的,但是角度不同.站在应用的角度,是控制反转,站在Spring容器的角度上,是依赖注入.

创建对象

创建对象的方式:

  1. 构造方法(默认方式)
  2. 静态工厂:通过静态方法创建对象
  3. 非静态工厂:非静态方法创建对象
  4. 注解

属性注入:

  1. 构造方法

  2. set方法

  3. 注解

常用的注入方式:

??使用set方法注入: 因为set方法可以根据需要的属性进行注入,而构造方法依赖构造器.必须要有set方法.

??注解(最常用),一般只能用于自己定义的代码.在源码中无法使用注解.

IOC常用注解:

??@Component : 组件 被该注解注释的类, 会创建对象对象放入到IOC容器

??@Controller : 表示控制层 被该注解注释的类, 会创建对象对象放入到IOC容器

??@Service : 表示Service 层 被该注解注释的类, 会创建对象对象放入到IOC容器

??@Repository : 表示持久化层 被该注解注释的类, 会创建对象对象放入到IOC容器

??@Autowired : 自动装配 默认type装配

??@Qualifier(名称) : 使用指定的名称装配对象

注意:

???标准化.

???标准化,在开发中,在流程上会结构清晰,条理分明.代码可读性提高了.

??在维护上,定位问题相对快准确,扩展程序相对轻松

以上是关于Spring总结的主要内容,如果未能解决你的问题,请参考以下文章

初识Spring源码 -- doResolveDependency | findAutowireCandidates | @Order@Priority调用排序 | @Autowired注入(代码片段

初识Spring源码 -- doResolveDependency | findAutowireCandidates | @Order@Priority调用排序 | @Autowired注入(代码片段

BootStrap实用代码片段(持续总结)

Spring boot:thymeleaf 没有正确渲染片段

回归 | js实用代码片段的封装与总结(持续更新中...)

What's the difference between @Component, @Repository & @Service annotations in Spring?(代码片段