Spring
1.为什么使用Spring、Spring的好处
● 非侵入式设计
Spring是一种非侵入式(non-invasive)框架,它可以使应用程序代码对框架的依赖最小化。
● 方便解耦、简化开发
Spring就是一个大工厂,可以将所有对象的创建和依赖关系的维护工作都交给Spring容器管理,大大的降低了组件之间的耦合性。
● 支持AOP
Spring提供了对AOP的支持,它允许将一些通用任务,如安全、事务、日志等进行集中式处理,从而提高了程序的复用性。
● 支持声明式事务处理
只需要通过配置就可以完成对事务的管理,而无需手动编程。
● 方便程序的测试
Spring提供了对Junit4的支持,可以通过注解方便的测试Spring程序。
● 方便集成各种优秀框架
Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts、Hibernate、MyBatis、Quartz等)的直接支持。
● 降低Java EE API的使用难度
Spring对Java EE开发中非常难用的一些API(如:JDBC、JavaMail等),都提供了封装,使这些API应用难度大大降低。
2.使用sprig
maven项目下使用spring
-
1.导入依赖包
-
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.4.RELEASE</version> </dependency>
-
-
2.创建核心配置文件
-
classpath的根目录下新建一个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" xmlns:comtext="http://www.springframework.org/schema/context" 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"> </beans>
-
3.IOC和DI 控制反转和依赖注入
Ioc—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想。
在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。
IOC的优点:
第一,资源集中管理,实现资源的可配置和易管理。
第二,降低了使用资源双方的依赖程度,也就是我们说的耦合度。
IOC的缺点:
1、创建对象的步骤变复杂了,不直观,当然这是对不习惯这种方式的人来说的。
2、因为使用反射来创建对象,所以在效率上会有些损耗。但相对于程序的灵活性和可维护性来说,这点损耗是微不足道的。
3、缺少IDE重构的支持,如果修改了类名,还需到XML文件中手动修改,这似乎是所有XML方式的缺憾所在。
1.创建一个bean、java类
public class MyBean {
public MyBean() {
System.out.println("调用Mybean的构造 --MyBean");}
public void say(){
System.out.println("hello---MyBean"); }
}
2.将java类交给spring管理(放到容器中)
在applicationContext配置文件中
<!-- 将类交给spring管理
id:唯一标识
class:类的全限定名-->
<bean id="myBean" class="com.yn._01beanTest.MyBean"></bean>
3.使用spring的bean工厂创建对象
-
1.第一种(过时,采用懒加载的方式创建bean)
-
//BeanFactory 采用懒加载的方式创建bean //拿到资源文件 Resource resource = new ClassPathResource("applicationContext.xml"); //创建bean工厂 BeanFactory beanFactory = new XmlBeanFactory(resource); //第一种 根据bean里面的id 拿到对应的bean MyBean myBean = (MyBean)beanFactory.getBean("myBean"); myBean.say(); //第二种 根据类名获取(根据类型) // 如果在配置文件中 class一样但是id不一样的bean 用这个方法会报错 MyBean bean = beanFactory.getBean(MyBean.class); bean.say(); // 第三种 id+类名精确获取 MyBean myBean3 = beanFactory.getBean("myBean", MyBean.class); myBean3.say();
-
2.第二种
-
//默认采用采用迫切加载的方式:启动就直接按照配置文件 创建bean
// 如果配置文件中 default-lazy-init=“true” 将会采用懒加载方式 -
//ApplicationContext ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml"); // //方式1 MyBean myBean = (MyBean)applicationContext.getBean("myBean"); myBean.say(); //方式2 MyBean myBean2 = applicationContext.getBean(MyBean.class); myBean2.say(); //方式3 MyBean myBean3 = applicationContext.getBean("myBean", MyBean.class); myBean3.say();
-
我们在使用ApplicationContext的时候,可以通过配置让它也变成与BeanFactory一样的懒加载:
配置一:让所有Bean都变成懒加载,只需要在<beans>标签中加入default-lazy-init=“true”:
<beans xmlns="http://www.springframework.org/schema/beans" .... default-lazy-init="true"> <bean id="myBean" class="com.yn._01beanTest.MyBean"></bean> </beans>
配置二:让其中一个Bean变成懒加载,在<bean>标签中加入lazy-init=“true”:
<bean id="myBean" class="com.yn._01beanTest.MyBean" lazy-init="true"></bean>
用注解来管理Bean
Controller就用 @Controller 注解
Service就用@Service注解
dao/mapper用@Repository
其他的用@Component
任意用一个都可以,但是为了代码可读性,最好分门别类的使用
依赖注入
配置文件来实现依赖注入
现在有两个java类并且已经交给spring管理
public class MyDaoBean {
public MyDaoBean() {
System.out.println("构造完成--MyDaoBean");}
public void say(){
System.out.println("hello----MyDaoBean");}}
public class MyService {
private MyDaoBean myDaoBean;
public MyService() {
System.out.println("构造完成--MyService");
}
public void say(){
System.out.println("hello----MyService");
myDaoBean.say(); }}
配置文件
<bean id="myBean" class="com.yn._01beanTest.MyBean"></bean>
<bean id="myService" class="com.yn._01beanTest.MyService" ></bean>
现在需求是 MyService中调用MyDaoBean的方法
不能通过new的方式,而是通过依赖注入
那么–》
public class MyService {
private MyDaoBean myDaoBean;
public MyDaoBean getMyDaoBean() {
return myDaoBean;
}
public void setMyDaoBean(MyDaoBean myDaoBean) {
this.myDaoBean = myDaoBean;
}
//通过配置文件来实现依赖注入
//这里get和set方法是必须的 因为配置文件底层就是用getset方法来关联的
//------------------------------------------------------------------------
public MyService() {
System.out.println("构造完成--MyService");
}
public void say(){
System.out.println("hello----MyService");
myDaoBean.say();
}
配置文件
<bean id="myBean" class="com.yn._01beanTest.MyBean"></bean>
<bean id="myService" class="com.yn._01beanTest.MyService" >
<property name="myDaoBean" ref="myDaoBean"/>
<!-- name 对应的是MyService这个类里面的 ref对应的是配置文件里面的bean-->
</bean>
这样就实现了依赖注入
注解实现依赖注入
//dao层的注解
@Repository
public class MyDaoBean {
public MyDaoBean() {
System.out.println("构造完成--MyDaoBean");
}
public void say(){
System.out.println("hello----MyDaoBean");
}
public void init(){
System.out.println("init 初始化");
}
public void distroy(){
System.out.println("distroy 销毁");
}
}
//注解为service
@Service
//@Scope("prototype")
//Scope作用域 prototype 多例模式 默认为单例
public class MyService {
//依赖注入 使用注解一定要在配置文件中开启
@Autowired //框架的注解
// @Resource //jdk自带的注解
@Qualifier("myDaoBean")
private MyDaoBean myDaoBean;
// Autowired与Resource区别
// Atuwired 先根据类型去找如果找到多个再根据名字去找bean(会出现 两个类实现同一个接口时 这里注入时写入的类型是接口名这个情况
// @Qualifier("myDaoBean") 用于指定具体的id名 )
// Resource 先直接去找名字
//------------------------------------------------------------------------
public MyService() {
System.out.println("构造完成--MyService");
}
public void say(){
System.out.println("hello----MyService");
myDaoBean.say();
}
配置文件中:
<!--开启注解扫描 需要指定包-->
comtext:component-scan base-package="com.yn._02annotation"></comtext:component-scan>
十分简便
Spring测试
1.导入测试包
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>compile</scope>
</dependency>
-
@RunWith:表示先启动Spring容器,把junit运行在Spring容器中;
-
@ContextConfiguration(“classpath:applicationContext.xml”):表示从CLASSPATH路径去加载资源文件;
-
Autowired:表示自动装配,自动从Spring容器中取出对应bean赋值给当前使用的属性;
Spring测试代码:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Test02 {
@Autowired
private ApplicationContext applicationContext;
@Autowired
private MyService myService;//直接依赖注入就可以用
@Test
public void test02_1(){
myService.say();
}
}
Bean的作用域
指的是配置的Bean是单例还是多例/原型
通过Bean元素中的scope属性指定:
-
singleton:默认值,单例
-
prototype:多例
-
<bean id="scopeBean" class="cn.ronghuanet._03_scope.MyScopeBean" scope="prototype"> </bean>
在单例模式下Spring会对bean的生命周期进行管理
在多例模式下spring只管创建,不会管理
bean的四种注入方式
1.普通配置
1.1定义类
1.2注册Bean
或是用注解
<!--扫描组件:通过指定包,就是找到本包或者子孙包下面加了注解Component及@Controller等注解的类,把它交给spring管理
就相当于我们xml当中一个一个配置-->
<context:component-scan base-package="com.ronghuanet._01beanconfigdetail"></context:component-scan>
@Component @Controller @Servcie @Repository
2.简单静态工厂
准备工厂
public class CarFactory {
//静态方法,返回一个对象
public static Car createCar(){
return new Car();
}
}
工厂配置
<!‐‐factory‐method:代表执行工厂中的方法,会把方法返回的对象设置成一个bean ‐‐>
<bean id="car" class="cn.ronghuanet._04_bean.b_test.CarFactory" factory‐method="createCar"> </bean>
3.简单实例工厂
public class CarFactory {
//普通方法返回一个对象
public Car createCar(){
return new Car();
}
}
<!‐‐创建工厂对象‐‐>
<bean id="carFactory" class="cn.ronghuanet._04_bean.c_test.CarFactory"> </bean>
<!‐‐调用对应工厂对象中的方法,返回一个bean对象‐‐>
<bean id="car" factory‐bean="carFactory" factory‐method="createCar" />
4.FactoryBean方法
//每个FactoryBean对应一个操作类型
public class CarFactoryBean implements FactoryBean<Car> {
//返回的bean对象实例
public Car getObject() throws Exception {
return new Car();
}
//返回的bean的类型
public Class<?> getObjectType() {
return Car.class;
}
//设置该bean对象是否是单例
public boolean isSingleton() {
return true;
}
}
<!‐‐这里咱们配置的是一个FactoryBean Spring会为当前这个class对象创建一个bean对象出来 同时,还会创建一个对象 该对象的类型由 getObjectType 方法决定 该对象的值由 getObject 方法决定 而方法isSingleton确定它是否是单例 ‐‐>
<bean id="car" class="cn.ronghuanet._04_bean.d_test.CarFactoryBean"></bean>
依赖注入
1.构造器注入
构造器注入有:参数索引注入 ,参数类型注入 , 参数名注入 三种注入方式
2.外部bean与内部bean
-
如果咱们注入的一个对象而不是简单属性,如何注入,有两种方式 外部bean和内部bean
-
如果会被多个地方使用,建议使用外部bean
3.各种属性注入
数组注入
<property name="arrays">
<array>
<value>xxx</value>
<value>yyy</value>
<value>zzz</value>
</array>
</property>
简写
<property name="arrays" value="A,B,C" />
List注入
<property name="list">
<list>
<value>xxx</value>
<value>aaa</value>
<value>bbbb</value>
</list>
</property>
set注入
<property name="set">
<set>
<value>xxx</value>
<value>aaa</value>
<value>bbbb</value>
</set>
</property>
List注入
<property name="otherBeanList">
<list>
<bean class="cn.ronghuanet._01_.OtherBean" />
<bean class="cn.ronghuanet._01_.OtherBean" />
<ref bean="otherBean" />
<ref bean="otherBean" />
</list>
</property>
Map<String,String>注入
<property name="map">
<map>
<entry key="xx" value="value1"></entry>
<entry key="yy" value="value2"></entry>
</map>
</property>
Properties注入
<property name="props2">
<props>
<prop key="Jpa.dialect">org.Jpa.dialect.HSQLDialect</prop>
<prop key="Jpa.driverClassName">com.mysql.jdbc.Driver中文 </prop>
</props>
</property>
简写方式 , 不支持中文
<property name="props1">
<value>
Jpa.dialect=org.Jpa.dialect.HSQLDialect
Jpa.driverClassName=com.mysql.jdbc.Driver
</value>
</property>
设值注入和构造注入。 这两种依赖注入的方式,并没有绝对的好坏,只是适应的场景有所不同。相比之下,设值注入有如下优点:
- 设值注入需要该Bean包含这些属性的setter方法
与传统的JavaBean的写法更相似,程序开发人员更容易理解、接收。通过setter方法设定依赖关系显得更加只管。
对于复杂的依赖关系,如果采用构造注入,会导致构造器国语臃肿,难以阅读。Spring在创建Bean实例时,需要同时实例化器依赖的全部实例,因而导致性能下降。而使用设值注入,则能避免这些问题
尤其是在某些属性可选的情况况下,多参数的构造器显得更加笨重
————————————————
构造注入也不是绝对不如设值注入,在某些特定的场景下,构造注入比设值注入更加优秀。构造注入有以下优势:
- 构造注入需要该Bean包含带有这些属性的构造器
构造注入可以在构造器中决定依赖关系的注入顺序,优先依赖的优先注入。例如,组件中其他依赖关系的注入,常常要依赖于DataSrouce的注入。采用构造注入,可以在代码中清晰的决定注入顺序。
对于依赖关系无需变化的Bean,构造注入更有用处。因为没有Setter方法,所有的依赖关系全部在构造器内设定。因此,无需担心后续的代码对依赖关系产生破坏。
依赖关系只能在构造器中设定,则只有组件的创建者才能改变组件的依赖关系。对组件的调用者而言,组件内部的依赖关系完全透明,更符合高内聚的原则。
————————————————
代理模式
代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。简单的说就是,我们在访问实际对象时,是通过代理对象来访问的,代理模式就是在访问实际对象时引入一定程度的间接性,因为这种间接性,可以附加多种用途。
————————————————
代理模式一般由三个角色组成:
- Subject(抽象主题角色):声明了真实主题和代理主题的共同接口。
- Proxy(代理主题角色):具体的代理类,它包含了真实主题的引用,也可以有自己的一些附属操作。
- RealSubject(真实主题角色):实现了真实的业务操作。
静态代理
什么是静态代理:
- 静态代理相当于是多写了一个代理类,在调用的时候调用的是代理类,在代理类中的处理还是原生的处理逻辑,不过在前后添加上需要添加的代码。
缺点:需要为每一个被代理的对象都创建一个代理类。
特点:
代理角色和真实角色都需要实现同一个接口,
真实角色专注于自己的事情,
代理角色目的就是帮助真实角色完成一件事情
多线程的实现方式2:实现一个接口Runnable 使用的就是"静态代理"的思想
————————————————
实体类
public class User {
private Integer id;
private String name;}
/*抽象主题角色
* */
public interface IUserService {
void save (User user);
}
/*真实对象
只负责核心业务
* */
public class UserServiceImpl implements IUserService{
@Override
public void save(User user) {
System.out.println("调用dao层新增数据。。"+user.toString());
}
}
/*
* 代理对象
* 负责事务管理
* */
public class UserServiceProxy implements IUserService {
private UserServiceImpl userService;
public UserServiceProxy(UserServiceImpl userService) {
this.userService = userService;
}
@Override
public void save(User user) {
try {
System.out.println("开启事务...");
//调用真实对象的方法,让真实对象干活(执行核心业务)
userService.save(user);
System.out.println("提交事务...");
} catch (Exception e) {
e.printStackTrace();
System.out.println("回滚事务....");
}finally {
System.out.println("关闭事务....");
}
}
}
@Test
public void test(){
UserServiceImpl realObj = new UserServiceImpl();//真实对象
UserServiceProxy userServiceProxy = new UserServiceProxy(realObj);
userServiceProxy.save(new User(12,"12324t"));
}
动态代理
什么是动态代理?
Java标准库提供了动态代理功能,允许在运行期动态创建一个接口的实例; 动态代理是通过 Proxy 创建代理对象,然后将接口方法“代理”给 InvocationHandler 完成的。
JDK动态代理
//动态代理
@Test
public void test02() {
// Proxy.newProxyInstance() 根据真实对象生成代理对象
/*需要的参数
* ClassLoader loader, //类加载器
Class<?>[] interfaces,// 多个接口,抽象主题角色接口(真实对象所需要的接口)
InvocationHandler h
*
* */
// 拿当前类获取类加载器
ClassLoader classLoader = MyTest.class.getClassLoader();// 获取类加载器
//获取真实对象的接口
UserServiceImpl userService = new UserServiceImpl();
Class<?>[] interfaces = userService.getClass().getInterfaces();
IUserService proxyInstance= (IUserService)Proxy.newProxyInstance(classLoader, interfaces, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//代理对象需要执行的代码
try {
System.out.println("开启事务...");
//调用真实对象的方法,让真实对象干活(执行核心业务)
method.invoke(userService,args);
System.out.println("提交事务...");
} catch (Exception e) {
e.printStackTrace();
System.out.println("回滚事务....");
}finally {
System.out.println("关闭事务....");
}
return null;
}
});
proxyInstance.save(new User(122,"scac"));
}
cglib动态代理
@Test
public void test03() {
//真实对象
IUserService realObj = new UserServiceImpl();
//事务管理器
// TxManager txManager = new TxManager();
//创建对象
Enhancer enhancer = new Enhancer(); //获取增强器
enhancer.setSuperclass(realObj.getClass()); //把真实类作为代理类父类,代理类就是子类,子类就可以通过supper调用父类方法
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
Object result = null;
//代理对象需要执行的代码
try {
System.out.println("开启事务...");
//调用真实对象的方法,让真实对象干活(执行核心业务)
method.invoke(realObj,objects);
System.out.println("提交事务...");
} catch (Exception e) {
e.printStackTrace();
System.out.println("回滚事务....");
}finally {
System.out.println("关闭事务....");
}
return result;
}
});
IUserService proxyObject = (IUserService) enhancer.create(); //创建代理对象
// proxyObject.add(new User(1L, "zs"));
}
静态代理总结:
1)代理类的信息在jvm运⾏之前就已经⽣成,逻辑由开发者实现;
2)代理类与⽬标类的定义应该严格参照规范,定义公共接⼝并实现它,需要代理的⽅法在接⼝中都要定义好;
静态代理原理:在代理类中包含⼀个⽬标类的对象引⽤,然后在使⽤时创建⼀个⽬标类对象并且创建⼀个代理类对象,并把⽬标类对象传给代
理类对象,然后将它赋予代理类中的⽬标类对象引⽤,然后代理类所代理的⽅法中通过其所包含的⽬标类对象引⽤调⽤⽬标类的⽅法,从⽽实现通过代理调⽤⽬标类⽅法的效果。
动态代理总结:
1) 动态代理是指 在java程序运⾏过程(程序已经启动在运⾏了)由jvm⽣成代理类的class信息,该class信息⽣成后是直接处于内存中的,并没有写⼊磁盘保存起来;然后通过反射⽅式实例化代理类对象,因为代理类的class信息已经存在于内存中,所以可以通过反射⽅式实例化。
这个应该怎么理解呢?
可以跟上⾯讲过的静态代理对⽐下,静态代理是需要开发⼈员⾃⼰实现代理类的逻辑的,且代理类的class信息是在程序运⾏之前就已经可以获取到的.java⽂件经过编译后可以得到.class⽂件;
⽽动态代理是不需要开发⼈员⾃⼰实现代理类的,也就是说使⽤动态代理⽅式的话,项⽬代码中是不存在代理类的.java⽂件的,既然代理类未由开发者实现,那么程序经过编译之后肯定也不会有代理类的.class⽂件,
也就是说经过编译之后程序未启动运⾏之前,关于代理类的信息我们⼀⽆所知,它是在程序运⾏过程中需要⽤到的时候才会由jvm动态⽣成的,⽽且⽣成之后也只存在于内存中,不会写到磁盘保存成.class⽂件,更加不会保存为.java⽂件;
在程序重启或者说发⽣了gc,这个代理类的class信息从内存中被卸载之后,关于这个代理类的信息就没有了,只有当代码再次访问到代理对象时,才⼜会重新⽣成代理类的class信息。
2)动态代理与静态代理的区别是什么?
上⾯已经讲述,不再赘述。
3)为什么需要引⼊动态代理?
这就不得不说到静态代理的弊端,我们引⼊新事物,必定是因为旧事物存在不合理之处,所以才引⼊新的事物来弥补它的缺陷。
那静态代理有什么缺陷呢?
我们知道静态代理是需要开发者⾃⼰实现代理类逻辑的,也就是说要对某个类进⾏代理的话,需要实现这个类相应的代理类;
如果⽬标类的数量很多的话,代理类的实现也必然得很多,可能会造成代码量过于庞⼤,可能会增加代码的冗余度…
再者,如果⽬标类需要代理的⽅法很多的话,代理类需要对这些⽅法⼀⼀实现代理逻辑,代理类的实现也将会很庞⼤。
考虑到这些问题,催⽣了动态代理这种⽅式,它相⽐于静态代理来说,由于不需要开发者⾃⼰再实现代理类了,所以在实际⼤型项⽬中可能代码量会⼤⼤减少。
————————————————
SpringAop
AOP的定义
AOP (Aspect Orient Programming),直译过来就是 面向切面编程,AOP 是一种编程思想,是面向对象编程(OOP)的一种补充。
面向切面编程,实现在不修改源代码的情况下给程序动态统一添加额外功能的一种技术,如下图所示:
AOP可以拦截指定的方法并且对方法增强,而且无需侵入到业务代码中,使业务与非业务处理逻辑分离,比如Spring的事务,通过事务的注解配置,Spring会自动在业务方法中开启、提交业务,并且在业务处理失败时,执行相应的回滚策略。
AOP的作用
AOP 采取横向抽取机制(动态代理),取代了传统纵向继承机制的重复性代码,其应用主要体现在事务处理、日志管理、权限控制、异常处理等方面。
主要作用是分离功能性需求和非功能性需求,使开发人员可以集中处理某一个关注点或者横切逻辑,减少对业务代码的侵入,增强代码的可读性和可维护性。
简单的说,AOP 的作用就是保证开发者在不修改源代码的前提下,为系统中的业务组件添加某种通用功能。
——
aop核心概念
1.连接点( JoinPoint )∶程序执行过程中的任意位置,粒度为执行方法、抛出异常、设置变量等在SpringAOP中,理解为方法的执行
2.切入点( Pointcut ) :匹配连接点的式子
在SpringAoP中,一个切入点可以只描述一个具体方法,也可以匹配多个方法
一个具体方法: com.demo.dao包下的BookDao接口中的无形参无返回值的save方法
匹配多个方法:所有的save方法,所有的get开头的方法,所有以Dao结尾的接口中的任意方法
所有带有一个参数的方法
3.通知( Advice ):在切入点处执行的操作,也就是共性功能
在SpringAOP中,功能最终以方法的形式呈现
4.通知类︰定义通知的类
5.切面(Aspect )︰描述通知与切入点的对应关系
4.AOP核心概念
1.目标对象(Target )∶原始功能去掉共性功能对应的类产生的对象,这种对象是无法直接完成最终工作的·代理(Proxy )︰目标对象无法直接完成工作,需要对其进行功能回填,通过原始对象的代理对象实现
概念:AOP(Aspect Oriented Programming)面向切面编程,一种编程范式作用︰在不惊动原始设计的基础上为方法进行功能增强
5.核心概念
代理( Proxy ) : SpringAOP的核心本质是采用代理模式实现的连接点( JoinPoint ) :在SpringAOP中,理解为任意方法的执行
切入点( Pointcut ) :匹配连接点的式子,也是具有共性功能的方法描述
通知(Advice ):若干个方法的共性功能,在切入点处执行,最终体现为一个方法切面( Aspect )︰描述通知与切入点的对应关系
目标对象(Target ):被代理的原始对象成为目标对象
————————————————
maven依赖
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.8</version>
</dependency>
public class User {
private Integer id;
private String name;
/*抽象主题角色
* */
import com.yn._03proxy.User;
public interface IUserService {
void save (User user);
void delete();
}
/*真实对象
只负责核心业务
* */
public class UserServiceImpl implements IUserService {
@Override
public void save(User user) {
System.out.println("调用dao层新增数据。。"+user.toString());
}
@Override
public void delete() {
System.out.println("删除数据....");
}
}
/*** 事务对象 */
public class TxManager {
public void begin(){
System.out.println("开启事务....");
}
public void commit(){
System.out.println("提交事务....");
}
// joinpoint可以让我们获取被增强方法相关的所有信息
public void rollback(){
System.out.println("回滚事务....");
}
public void close(){
System.out.println("关闭事务....");
}
public Object around(ProceedingJoinPoint joinPoint){
//System.out.println(joinPoint.getTarget());
//调用的类
//System.out.println(Arrays.asList(joinPoint.getArgs()));
//参递的参数
//System.out.println(joinPoint.getSignature());
//方法签名
Object object = null;
try {
begin();
object = joinPoint.proceed();
//执行相应的代码
commit();
} catch (Throwable e) {
rollback();
}finally{
close();
}
return object;
}
}