目录
1.2.2 通过FileSystemXmlApplicationContext创建
1.spring核心容器
1.1 BeanFactory
其主要是一个管理Bean的工厂,主要负责初始化各种Bean,并调用他们的生命周期方法,语法如下:
//1.加载bean工厂
BeanFactory beanfactory=new ClassPathXmlApplicationContext("app*.xml");
1.2 ApplicationContext
ApplicationContext是BeanFactory的子接口,也被称为应用上下文,是另一种常用的Spring的核心容器。它不仅包含了BeanFactory的所有功能,还添加了对国际化、资源访问、事件传播等方面的支持。语法如下:
1.2.1 通过ClassPathXmlApplicationContext创建(常用)
//1.加载bean工厂
ApplicationContext applicationcontext=new ClassPathXmlApplicationContext("app1.xml");
1.2.2 通过FileSystemXmlApplicationContext创建
FileSystemXmlApplicationContext会从指定的文件系统路径(绝对路径)区寻找指定的XML配置文件,找到并装载完成ApplicationContext的实列化工作,其灵活性较差,语法如下:
//1.加载bean工厂
ApplicationContext applicationcontext=new FileSystemXmlApplicationContext(String configLocation);
2.XML的配置信息
以下示例显示了基于 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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="..." class="..."> (1) (2)
</bean>
<bean id="..." class="...">
</bean>
</beans>
-
(1)
id
属性是标识单个 bean 定义的字符串。 -
(2)
class
属性定义 bean 的类型并使用完全限定的类名。
id
属性的值是指协作对象。在此示例中未显示用于引用协作对象的 XML。
3.spring的依赖注入(DI)
1.依赖注入:
IOC的作用:降低程序之间的耦合(依赖关系)
概念:依赖关系的管理交给spring维护,在当前类需要用到其他类的对象,由spring为我们提供,只需在配置文件中说明关系的维护;
2.能够注入的数据有三类:
1) 基本类型和string
2) 其他bean类型(在配置文件中或者注解配置过的bean)
3)复杂集合类型
3.两种注入方式
1)使用构造函数
1.先建立一个user类
public class user {
private String username;
private int password;
private List<String> list;
/*
* 1.使用构造注入
* 1.1提供带所有参数的有参构造方法
*/
public user(String username, int password, List<String> list) {
super();
this.username = username;
this.password = password;
this.list = list;
}
@Override
public String toString() {
return "user [username=" + username + ", password=" + password + ", list=" + list + "]";
}
}
2.配置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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
<!--使用构造注入的方式 -->
<bean id="user1" class="com.ds.spring.user">
<constructor-arg index="0" value="tom"/>
<constructor-arg index="1" value="123456"/>
<constructor-arg index="2">
<list>
<value>"constructorvalue1"</value>
<value>"constructorvalue2"</value>
</list>
</constructor-arg>
</bean>
</beans>
3.运行输出
@Test
public void testem() {
//1.加载bean工厂
ApplicationContext beanfactory=new ClassPathXmlApplicationContext("app5.xml");
//2.获取bean
user u1=(user) beanfactory.getBean("user1");
System.out.println(u1);
}
2)set方法注入(常用)
设值注入是IoC容器使用成员变量的setter方法来注入被依赖对象。需满足两点:
(1)Bean类必须提供一个默认的无参构造方法。
(2)Bean类必须为需要注入的属性提供对应的setter方法。
1.先建一个user类
package com.ds.spring;
import java.util.List;
public class user {
private String username;
private int password;
private List<String> list;
/*
* 2.使用设置注入
* 2.1提供默认的空参构造方法
* 2.2为所有属性提供setter方法
*/
public user() {
super();
// TODO Auto-generated constructor stub
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public int getPassword() {
return password;
}
public void setPassword(int password) {
this.password = password;
}
public List<String> getList() {
return list;
}
public void setList(List<String> list) {
this.list = list;
}
@Override
public String toString() {
return "user [username=" + username + ", password=" + password + ", list=" + list + "]";
}
}
2.进行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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
<!--使用设置注入 -->
<bean id="user2" class="com.ds.spring.user">
<property name="username" value="jack"/>
<property name="password" value="654321"/>
<property name="list">
<list>
<value>"setlistvalue1"</value>
<value>"setlistvalue2"</value>
</list>
</property>
</bean>
</beans>
3.运行
public class test {
@Test
public void teste() {
//1.加载bean工厂
ApplicationContext beanfactory=new ClassPathXmlApplicationContext("app5.xml");
//2.获取bean
user u2=(user)beanfactory.getBean("user2");
System.out.println(u2);
}
}
4.基于Annotation的装配
1)Spring中常用注解如下
-
@Commponent相当于new了个对象,也就是相当于<bean id=""/>中id的值,(不写括号里的名字的话默认类名的小写)
-
@Repository功能与Commponent相同,但是其常用于数据访问层(DAO层)
-
@Service功能与Commponent相同,其常用于业务层(Service层)
-
@Controller功能与Commponent相同,其常用于控制层
-
@Autowired,该注解默认使用按类型自动装配Bean的方式。 使用该注解完成属性注入时,类中无需setter。当然,若属性有setter,则也可将其加到setter上。
-
@Qualifier的value属性用于指定要匹配的Bean的id值。同样类中无需setter,也可加到setter上。@Autowired与@Qualifier相当于@Resource(name=" ")
-
@Scope,其value属性用于指定作用域。默认为singleton
-
@Value,该注解的value属性用于指定要注入的值。
-
@Resource是java自带的注解
@Resource注解既可以按名称匹配Bean,也可以按类型匹配Bean。使用该注解,要求JDK必须是6及以上版本。 (1)按类型注入域属性 @Resource注解若不带任何参数,看 Spring 容器中的 bean 中的 id 与@ Resource 要注解的那个变量属性名是否相 同,如相同,匹配成功;如不同 看 spring 容器中 bean 的 id 对应的类型是否与@ Resource 要注解的那个变量属性对应的类型是否相等,若相等,匹配成功,若不相等,匹配失败。
(先比较名字cat1和cat发现不同,然后就比较类名Cat和Cat发现相同,匹配成功)
2)按名称注入域属性 @Resource注解指定其name属性,则name的值即为按照名称进行匹配的Bean的id。
如下一个例子:
1.建立一个Cat类
package com.hkd.zhujie;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component("cat1")//指定id为cat1
public class Cat {
@Value("波斯猫")
String name;
public void shoutc() {
System.out.println(name+"喵喵喵!");
}
}
2.建立一个Dog类
package com.hkd.zhujie;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component//默认id为dog
public class Dog {
@Value("金毛")
String name;
public void shoutd() {
System.out.println(name+"汪汪汪!");
}
}
3.建立Animal类,并引入Cat和Dog‘类
package com.hkd.zhujie;
import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class Animal {
//@Autowired//默认按类名进行找
@Resource//默认先根据id和名字找,再根据类名找
Dog dog;
// @Autowired
// @Qualifier("cat1")//按id名进行找
@Resource(name="dog")//按id名找
Cat cat;
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
public Cat getCat() {
return cat;
}
public void setCat(Cat cat) {
this.cat = cat;
}
public void shouta() {
dog.shoutd();
cat.shoutc();
}
}
4.扫描包(app6.xml)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!--扫描包 -->
<!--使用context命名空间,在配置文件中开启相应的注解处理器 -->
<context:component-scan base-package="com.hkd.zhujie">
</context:component-scan>
</beans>
5.测试
package com.hkd.zhujie;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class test {
public static void main(String[] args) {
ApplicationContext app=new ClassPathXmlApplicationContext("app6.xml");
Animal a=(Animal)app.getBean("animal");
a.shouta();
}
}
5.使用JavaConfig配置
1)其完全不使用Spring的XML进行配置,全部交给Java来做,JavaConfig是Spring的一个子项目,在Spring4后,它成了一个核心功能。
1.建一个user类
package com.ds.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
public class user {
@Value("李白")
String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "user [name=" + name + "]";
}
}
2.再建一个config类来配置
package com.ds.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration//代表的是一个配置类,相当于XML文件
public class config {
@Bean//这个方法的名字,相当于bean标签中的id属性
//返回值相当于bean标签的class属性
public user getuser() {
return new user();
}
}
3.运行
package com.ds.config;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class test {
public static void main(String[] args) {
ApplicationContext app=new AnnotationConfigApplicationContext(config.class);
user u=(user)app.getBean("getuser");//方法名
System.out.println(u.getName());
}
}
4.代理
1)其含义就是通过第三方来代理我们的工作,用如下例子来说明
1.先写一个接口userservice
package com.fbw.agent;
public interface userservice {
void add();
void delete();
void update();
void quary();
}
2.userserviceimp实现这个接口
package com.fbw.agent;
//不能改源代码,创一个代理类
public class userserviceimp implements userservice {
public void add() {
// TODO Auto-generated method stub
//System.out.println("使用了add方法");一般会这样写,但这样会比较臃肿,而且修改了源码,为了避免这些所以引出了代理
System.out.println("add a user");
}
public void delete() {
// TODO Auto-generated method stub
//System.out.println("使用了delete方法");
System.out.println("delete a user");
}
public void update() {
// TODO Auto-generated method stub
//System.out.println("使用了update方法");
System.out.println("update a user");
}
public void quary() {
// TODO Auto-generated method stub
//System.out.println("使用了quary方法");
System.out.println("quary a user");
}
}
正常的话直接new对象就可以调用方法了,但现在有一个在每个方法上都加上“使用了...方法“的输出,而且是在不改变源码(修改源码是大忌)的条件下的需求,此时就要引入代理,代理可分为静态代理和动态代理:
1)静态代理
3.接上面的例子,创建一个名为userserviceagent的代理类来处理需求
package com.fbw.agent;
//代理类
public class userserviceagent implements userservice {
userserviceimp usp;
public void setUsp(userserviceimp usp) {
this.usp = usp;
}
//引入需求
public void log(String msg) {
System.out.println("使用了"+msg+"方法");
}
@Override
public void add() {
// TODO Auto-generated method stub
log("add");
usp.add();
}
@Override
public void delete() {
// TODO Auto-generated method stub
log("delete");
usp.delete();
}
@Override
public void update() {
// TODO Auto-generated method stub
log("update");
usp.update();
}
@Override
public void quary() {
// TODO Auto-generated method stub
log("quary");
usp.quary();
}
}
此时加入的需求就直接引用到了代理类里,源码也不必修改
4.测试
package com.fbw.agent;
public class test {
public static void main(String[] args) {
//要代理的类,真实角色
userserviceimp usi=new userserviceimp();
//代理类
userserviceagent usa=new userserviceagent();
//设置要代理的类
usa.setUsp(usi);
//调用方法
usa.add();
}
}
2)动态代理
有静态代理可以看出,其虽然实现了需求,但是其比较繁琐每次需要完成需求都要建立一个代理类,所以就引入了动态代理,动态代理是在反射的基础上完成的。
3.接上面的例子我们可以创建一个动态的代理万能类其需要实现InvocationHandler接口,如下(类名为ProxyInvocationHandler)
package com.fbw.agent;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import jdk.nashorn.internal.runtime.linker.InvokeByName;
//动态的工具类,自动生成代理类
public class ProxyInvocationHandler implements InvocationHandler {
//被代理的接口
private Object target;
public void setTarget(Object target) {
this.target = target;
}
//生成得到代理类
public Object getproxy() {
/*
* newProxyInstance,方法有三个参数:
*
* loader: 用哪个类加载器去加载代理对象
*
* interfaces:动态代理类需要实现的接口
*
* h:动态代理方法在执行时,会调用h里面的invoke方法去执行
*
* 其返回的是代理类
*/
return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(), this);
}
//处理代理实例,并返回结果
@Override
public Object invoke(Object arg0, Method arg1, Object[] arg2) throws Throwable {
// TODO Auto-generated method stub
/*
* invoke三个参数:
arg0:就是代理对象,newProxyInstance方法的返回对象
arg1:调用的方法
arg2: 方法中的参数
method.invoke(Object obj,Object args[])的作用就是调用method类代表的方法,
其中obj是接口名,args调用的obj中的方法的,也就是说其返回的是obj接口中的args方法
*/
//通过arg1.getName()来获取调用的方法名
log(arg1.getName());
Object result=arg1.invoke(target, arg2);
return result;
}
public void log(String msg) {
System.out.println("执行了"+msg+"方法");
}
}
-
target:代表的是要被代理的接口
-
setTarget(Object target):为了使将要生成的代理类也实现接口
-
getproxy():其return的是要代理的类,其目的是为了的得到要代理的类,即userserviceimp类
-
newProxyInstance(参数1,参数2,参数3):其三个参数分别代表:
-
用哪个类加载器去加载代理对象,即ProxyInvocationHandler类
-
动态代理的类需要实现的接口,即service接口
-
动态代理方法在执行时,会调用h里面的invoke方法去执行(在这个例子里就是this,实际上是ProxyInvocationHandler类中的invoke()方法)
-
-
this:代表的就是本类
-
getClass():返回值是类
-
getClassLoader():返回类的加载器
-
getInterfaces():返回类的接口
-
invoke(Object arg0, Method arg1, Object[] arg2):
-
arg0:就是代理对象,也就是target
-
arg1:调用的方法
-
arg3:方法中的参数
-
-
arg1.invoke(Object obj,Object args[])的作用就是调用arg1类代表的方法,其中obj是接口名,args调用的obj中的方法的,也就是说其返回的是obj接口中的args方法(用了反射,就是Method arg1.invoke())。就是使代理类在拥有userserviceimp中的所有方法的同时也能增加方法。
-
arg1.getName():调用方法的名字
4.测试
package com.fbw.agent; public class test1 { public static void main(String[] args) { //真实角色 userserviceimp u=new userserviceimp(); //生成代理类的工具,代理角色现在不存在 ProxyInvocationHandler pih=new ProxyInvocationHandler(); //真实角色已经实现了接口,代理角色也要实现接口,使将要生成的代理类也实现接口,现在其也代理了这个接口,并有了真实角色的方法 pih.setTarget(u); //用接口强转,动态生成代理类,接口是连接真实角色和代理工具的桥梁 userservice p=(userservice) pih.getproxy(); p.add(); } }
流程:先new真实角色和代理工具,然后调用代理工具中的setTaget(u)方法把实现userservice接口的类的对象传入(使代理对象实现接口),代理类对象的getproxy()方法会返回生成代理对象,而这个代理对象在生成时会调用invoke()方法,这个invoke()方法会使代理类对象拥有userserviceimp中的所有方法,也能使其拥有userserviceimp,中没有的方法如本例的log()方法。
5.AOP
aop是面向切面的编程,其实它和代理很像,都是要过第三方类在不改变源代码的情况下完成需求。
目前流行的是Spring AOP和AspectJ,Spring AOP使用的是纯java实现,不需要专门的编译过程和类的加载器,在运行期间通过代理方式向目标类织入增强代码。
AspectJ是基于java语言的AOP框架,AspectJ扩展了java语言,提供了专门的编译器,并在编译时提供了横向代码的织入。
spring有五种通知方法:
-
Around 环绕通知 org.aopalliance.intercept.MethodInterceptor 拦截对目标方法调用,可用于日志、事务管理等功能
-
Before 前置通知 org.springframework.aop.MethodBeforeAdvice 在目标方法调用前调用,可用于权限管理等功能
-
After 后置通知 org.springframework.aop.AfterReturningAdvice 在目标方法调用后调用,可用于关闭流,上传文件,删除临时文件等功能
-
Throws 异常通知 org.springframework.aop.ThrowsAdvice 当目标方法抛出异常时调用,可以应用于处理异常记录日志等功能
-
引介通知 org.springframework.aop.IntroductionInterceptor 在目标类中添加一些新的方法和属性,可以应用于修改老版本程序
以下例子都是围绕这五个通知来进行
1.使用Spring的API接口
1)首先先建立userservice接口
package com.fbw.aop;
public interface userservice {
void add();
void delete();
void update();
void quary();
}
2)建立serviceimp类来实现接口
package com.fbw.aop;
public class userserviceimp implements userservice {
public void add() {
// TODO Auto-generated method stub
System.out.println("add a user");
}
public void delete() {
// TODO Auto-generated method stub
System.out.println("delete a user");
}
public void update() {
// TODO Auto-generated method stub
System.out.println("update a user");
}
public void quary() {
// TODO Auto-generated method stub
System.out.println("quary a user");
}
}
3)建立两个类(类都要继承通知类)来验证(本例子用的是前置通知和后置通知):
package com.fbw.aop;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
public class log implements MethodBeforeAdvice {
//arg0:要执行的目标对象的方法
//arg1:参数
//arg2:目标对象
@Override
public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
// TODO Auto-generated method stub
//输出哪个包下的方法被执行
System.out.println(arg2.getClass().getName()+"的"+arg0.getName()+"被执行了");
}
}
package com.fbw.aop;
import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;
public class afterlog implements AfterReturningAdvice {
//arg0:返回值
@Override
public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable {
//输出执行的方法和返回值
System.out.println(arg1.getName()+"方法被执行了,返回结果为:"+arg0);
}
}
4)配置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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<!--注册bean -->
<bean id="ui" class="com.fbw.aop.userserviceimp"></bean>
<bean id="log" class="com.fbw.aop.log"></bean>
<bean id="afterlog" class="com.fbw.aop.afterlog"></bean>
<!--方式一:使用Spring API接口 -->
<!--配置aop -->
<aop:config>
<!-- 切入点:expression:表达式,execution(要执行的位置) -->
<aop:pointcut expression="execution(* com.fbw.aop.userserviceimp.*(..))" id="pointcut"/>
<!-- 执行环绕 advice-ref里是要执行的类名-->
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterlog" pointcut-ref="pointcut"/>
</aop:config>
</beans>
5)测试
package com.fbw.aop;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class test {
public static void main(String[] args) {
ApplicationContext app=new ClassPathXmlApplicationContext("aop.xml");
userservice u=(userservice)app.getBean("ui");
u.add();
}
}
2.使用自定义类
1)JoinPoint 对象
JoinPoint对象封装了SpringAop中切面方法的信息,在切面方法中添加JoinPoint参数,就可以获取到封装了该方法信息的JoinPoint对象. 常用api:
方法名 | 功能 |
---|---|
Signature getSignature(); | 获取封装了署名信息的对象,在该对象中可以获取到目标方法名,所属类的Class等信息 |
Object[] getArgs(); | 获取传入目标方法的参数对象 |
Object getTarget(); | 获取被代理的对象 |
Object getThis(); | 获取代理对象 |
2)ProceedingJoinPoint对象
ProceedingJoinPoint对象是JoinPoint的子接口,该对象只用在@Around的切面方法中, 其中添加了 Object proceed() throws Throwable //执行目标方法
Object proceed(Object[] var1) throws Throwable //传入的新的参数去执行目标方法
两个方法.
1)定义一个div类用来构造5种通知的方法
package com.fbw.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
public class div {
//前置通知
void before(JoinPoint joinpoint) {
System.out.println("前置通知:模拟执行权限检查。。。。");
System.out.println("目标类是:"+joinpoint.getTarget());
System.out.println("被植入增强处理的目标方法是:"+joinpoint.getSignature().getName());
}
//后置通知
void after(JoinPoint joinpoint) {
System.out.println("后置通知:模拟记录日志。。。。");
System.out.println("被植入增强处理的目标方法为:"+joinpoint.getSignature().getName());
}
//环绕通知
/*
* ProceedingJoinPoint是JoinPoint的一个子接口,表示可执行的目标方法 其必须是object类型的返回值
*/
Object round(ProceedingJoinPoint proceedingjoinpoint) throws Throwable {
System.out.println("环绕开始:执行目标之前,模拟开启事务");
//执行当前目标方法
Object obj=proceedingjoinpoint.proceed();
System.out.println("环绕结束:执行目标方法之后,模拟关闭事务");
return obj;
}
//异常通知
void yc(JoinPoint joinpoint,Throwable e) {
System.out.println("出现了异常,异常信息是:"+e.getMessage());
}
//最终通知
void fianlnotice() {
System.out.println("通知:结束了!!!");
}
}
2)设置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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<!--注册bean -->
<bean id="ui" class="com.fbw.aop.userserviceimp"></bean>
<bean id="diy" class="com.fbw.aop.div"></bean>
<aop:config>
<!-- 自定义切面。ref 要引入的类 -->
<aop:aspect ref="diy">
<!-- 切入点 ,expression中是要增强的方法 -->
<aop:pointcut expression="execution(* com.fbw.aop.userserviceimp.*(..))" id="point"/>
<!-- 通知 -->
<aop:before method="before" pointcut-ref="point"/>
<aop:after-returning method="after" pointcut-ref="point" returning="returnval"/>
<aop:around method="round" pointcut-ref="point"/>
<aop:after-throwing method="yc" pointcut-ref="point" throwing="e"/>
<aop:after method="fianlnotice" pointcut-ref="point"/>
</aop:aspect>
</aop:config>
</beans>
3)测试
package com.fbw.aop;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class test {
public static void main(String[] args) {
ApplicationContext app=new ClassPathXmlApplicationContext("aop.xml");
userservice u=(userservice)app.getBean("ui");
u.add();
}
}
3.使用注解
1)创建一个使用注解的类
package com.fbw.aop;
import org.aspectj.lang.JoinPoint;
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.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class a {
@Pointcut("execution(* com.fbw.aop.userserviceimp.*(..))")//相当于切入点,需要一个空的方法
public void my() {
}
@Before("my()")
//前置通知
void before(JoinPoint joinpoint) {
System.out.println("前置通知:模拟执行权限检查。。。。");
System.out.println("目标类是:"+joinpoint.getTarget());
System.out.println("被植入增强处理的目标方法是:"+joinpoint.getSignature().getName());
}
@AfterReturning("my()")
//后置通知
void after(JoinPoint joinpoint) {
System.out.println("后置通知:模拟记录日志。。。。");
System.out.println("被植入增强处理的目标方法为:"+joinpoint.getSignature().getName());
}
//环绕通知
/*
* ProceedingJoinPoint是JoinPoint的一个子接口,表示可执行的目标方法 其必须是object类型的返回值
*/
@Around("my()")
Object round(ProceedingJoinPoint proceedingjoinpoint) throws Throwable {
System.out.println("环绕开始:执行目标之前,模拟开启事务");
//执行当前目标方法
Object obj=proceedingjoinpoint.proceed();
System.out.println("环绕结束:执行目标方法之后,模拟关闭事务");
return obj;
}
@AfterThrowing(value = "my()",throwing = "e")
//异常通知
void yc(JoinPoint joinpoint,Throwable e) {
System.out.println("出现了异常,异常信息是:"+e.getMessage());
}
//最终通知
@After("my()")
void fianlnotice() {
System.out.println("通知:结束了!!!");
}
}
2)配置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: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-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!--也可以在userservice类中使用@component注解 -->
<bean id="ui" class="com.fbw.aop.userserviceimp"></bean>
<context:component-scan base-package="com.fbw.aop">
</context:component-scan>
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
3)测试运行
package com.fbw.aop;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class test {
public static void main(String[] args) {
/*
* ApplicationContext app=new ClassPathXmlApplicationContext("aop.xml");
* userservice u=(userservice)app.getBean("ui"); u.add();
*/
ApplicationContext app=new ClassPathXmlApplicationContext("a.xml");
userservice u=(userservice)app.getBean("ui");
u.add();
}
}