aop的注解方式实现
spring也支持注解方式实现aop,相对于配置文件的方式,注解配置更加的轻量级,配置修改更加的方便,是目前最流行的方式。
a.开启aop的注解配置方式
<!--注解方式配置aop开关 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
b.将指定的类标志为一个切面,并配置id
@Aspect
public class FirstAspect {
@Pointcut("execution(* cn.tedu.service..*.*(..))")
public void mx(){
}
c.配置通知 指定切入点规则
前置通知 @Before
环绕通知@Around
后置通知@AfterReturning
异常通知@AftereThrowing
最终通知@After
代码实现:
package cn.tedu.aspect;
//切面类
import java.lang.reflect.Method;
import java.util.Arrays;
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.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import cn.tedu.domain.User;
@Component
@Aspect
public class FirstAspect {
@Pointcut("execution(* cn.tedu.service..*.*(..))")
public void mx(){
}
/**
* 前置
* @param jp
*/
@Before("mx()")
public void before(JoinPoint jp){
System.out.println("前置通知1..");
//获取目标对象
Object targetObj=jp.getTarget();
System.out.println(targetObj);
//获取目标方法
MethodSignature msig=(MethodSignature) jp.getSignature();
Method m=msig.getMethod();
System.out.println(m.getName());
System.out.println(m.getReturnType());
System.out.println(Arrays.asList(m.getParameterTypes()));
}
/**
* 环绕
* @param pjp
* @return
* @throws Throwable
*/
@Around("mx()")
public Object around(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("环绕通知1...before..");
//执行目标方法
Object retuObj=pjp.proceed();
System.out.println("环绕通知1...after..");
return retuObj;
//return new User(33,"zsf","sf","dsf");//慎用,这里不是service层
}
/**
* 后置
*/
@AfterReturning(value="mx()",returning="reObj")
public void afterReturning(JoinPoint jp,Object reObj){
System.out.println("后置通知1..."+reObj);
Object obj=jp.getTarget();
System.out.println(obj);
MethodSignature signature=(MethodSignature) jp.getSignature();
Method method=signature.getMethod();
System.out.println(method.getName());
System.out.println(method.getReturnType());
System.out.println(Arrays.asList(method.getParameterTypes()));
}
/**
* 异常
*/
@AfterThrowing(value="mx()",throwing="e")
public void afterThrowing(JoinPoint jp,Throwable e){
System.out.println("异常通知1..."+e.getMessage());
}
/**
* 最终
*/
@After("mx()")
public void after(){
System.out.println("最终通知1...");
}
}
案例aop:
1.异常信息收集
有异常抛出,根据异常信息记录日志
代码实现:
package cn.tedu.aspect;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class FirstAspect {
@Pointcut("execution(* cn.tedu.service..*.*(..))")
public void mx(){
}
private Logger logger=Logger.getLogger(FirstAspect.class);
@AfterThrowing(value="mx()",throwing="e")
public void afterThrowing(JoinPoint jp,Throwable e){
Object obj=jp.getTarget();
MethodSignature signature=(MethodSignature) jp.getSignature();
logger.error("在访问["+obj+"]的["+signature.getMethod().getName()+"]方法时抛出了["+e.getMessage()+"]异常");
}
}
package cn.tedu.service;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService{
@Override
public void add(){
System.out.println("增加用户");
//int i=1/0;
}
}
package cn.tedu.web;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import cn.tedu.service.UserService;
@Controller
public class UserServlet {
@Autowired
UserService userService=null;
public void addUser(){
userService.add();
}
}
package cn.tedu.test;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.tedu.web.UserServlet;
public class test01 {
@Test
public void test01(){
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
UserServlet userServlet=(UserServlet) context.getBean("userServlet");
userServlet.addUser();
}
}
配置:
<!-- 配置ioc -->
<context:component-scan base-package="cn.tedu.web"></context:component-scan>
<context:component-scan base-package="cn.tedu.service"></context:component-scan>
<context:component-scan base-package="cn.tedu.dao"></context:component-scan>
<context:component-scan base-package="cn.tedu.aspect"></context:component-scan>
<!--注解方式配置aop开关 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
2.方法执行所用的时间
package cn.tedu.aspect;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class FirstAspect2 {
@Pointcut("execution(* cn.tedu.service..*.*(..))")
public void mx(){
}
@Around(value="mx()")
public void around(ProceedingJoinPoint pjp) throws Throwable{
long start=System.currentTimeMillis();
Object obj=pjp.proceed();
long end=System.currentTimeMillis();
long useTime=end-start;
System.out.println("调用["+pjp.getTarget()+"]的["+pjp.getSignature().getName()+"]所用时间为["+useTime+"]");
}
}
package cn.tedu.service;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService{
@Override
public void add(){
System.out.println("增加用户");
//int i=1/0;
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
3.实现事务控制(原代码在SpringDay04_03aop_demo项目中)
通过aop实现事务控制,通过注解来标识方法是否需要事务
在切面中通过判断目标方法是否具有事务注解决定是否执行事务
通过事务管理器管理事务防止耦合
代码实现
package cn.tedu.aspect;
import java.lang.reflect.Method;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import cn.tedu.anno.Trans;
import cn.tedu.util.TransactionManager;
@Component
@Aspect
public class TransAspect {
@Around(value="execution(* cn.tedu.service..*.*(..))")
public Object around(ProceedingJoinPoint pjp) throws Throwable{
//获取目标对象
Object target=pjp.getTarget();
//获取当前方法(接口上的方法)----注解在实现类的方法上
MethodSignature signature=(MethodSignature) pjp.getSignature();
Method method=signature.getMethod();
//在目标身上获取该方法(实现类上的方法)
Method instance_method=target.getClass().getMethod(method.getName(), method.getParameterTypes());
//判断当前方法上有没有@Tran修饰
if(method.isAnnotationPresent(Trans.class)||instance_method.isAnnotationPresent(Trans.class)){
try {
TransactionManager.startTran();
Object reObj=pjp.proceed();
TransactionManager.commitTran();
return reObj;
} catch (Exception e) {
TransactionManager.rollbacktTran();
throw e;
}finally{
TransactionManager.release();
}
}else{//没有注解说明不需要事务,不管理事务
try{
Object reObj=pjp.proceed();
return reObj;
}finally{
TransactionManager.release();
}
}
}
}
package cn.tedu.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.springframework.stereotype.Repository;
import cn.tedu.domain.User;
import cn.tedu.util.JDBCUtils;
import cn.tedu.util.TransactionManager;
@Repository
public class UserDaoImpl implements UserDao{
@Override
public void addUser(User user) {
Connection conn=null;
PreparedStatement ps=null;
ResultSet rs=null;
//注册数据库驱动
//获取数据库连接
try {
conn=TransactionManager.getConn();
ps=conn.prepareStatement("insert into user values(?,?,?)");
ps.setInt(1, user.getId());
ps.setString(2, user.getName());
ps.setInt(3, user.getAge());
ps.executeUpdate();
//需求:报异常不想让他传入数据库,可以通过事务处理
//int i=1/0;
} catch (SQLException e) {
throw new RuntimeException(e);
}finally{
JDBCUtils.close(null, ps, rs);
}
}
@Override
public void delUser(int id) {
Connection conn=null;
PreparedStatement ps=null;
try {
conn=TransactionManager.getConn();
ps=conn.prepareStatement("delete from user where id=?");
ps.setInt(1,id);
ps.executeUpdate();
//需求:报异常不想让他传入数据库,可以通过事务处理
//int i=1/0;
} catch (SQLException e) {
throw new RuntimeException(e);
}finally{
JDBCUtils.close(null, ps,null);
}
}
@Override
public User queryUser(int id) {
Connection conn=null;
PreparedStatement ps=null;
ResultSet rs=null;
//注册数据库驱动
//获取数据库连接
try {
conn=TransactionManager.getConn();
ps=conn.prepareStatement("select * from user where id=?");
ps.setInt(1, id);
rs=ps.executeQuery();
User user=null;
if(rs.next()){
user=new User();
user.setId(rs.getInt("id"));
user.setName(rs.getString("name"));
user.setAge(rs.getInt("age"));
}
return user;
//需求:报异常不想让他传入数据库,可以通过事务处理
//int i=1/0;
} catch (SQLException e) {
throw new RuntimeException(e);
}finally{
JDBCUtils.close(null, ps, rs);
}
}
}
package cn.tedu.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import cn.tedu.anno.Trans;
import cn.tedu.dao.UserDao;
import cn.tedu.domain.User;
@Service
public class UserServiceImpl implements UserService{
@Autowired
UserDao userDao=null;
@Trans
@Override
public void addUser(User user){
userDao.addUser(user);
}
@Override
public void delUser(int id) {
userDao.delUser(id);
}
@Override
public User queryUser(int id) {
return userDao.queryUser(id);
}
}
package cn.tedu.util;
import java.sql.Connection;
//事务管理提交回滚
public class TransactionManager {
private static Connection conn=JDBCUtils.getConn();
private TransactionManager(){
}
public static void startTran(){
try {
conn.setAutoCommit(false);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static void commitTran(){
try {
conn.commit();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static void rollbacktTran(){
try {
conn.rollback();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static Connection getConn(){
return conn;
}
public static void release(){
JDBCUtils.close(conn, null, null);
}
}
package cn.tedu.util;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class JDBCUtils {
private JDBCUtils(){
}
private static DataSource datasource=new ComboPooledDataSource();
public static Connection getConn(){
try {
return datasource.getConnection();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public static void close(Connection conn,Statement stat,ResultSet rs){
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
rs=null;
}
}
if(stat!=null){
try {
stat.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
stat=null;
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
conn=null;
}
}
}
}
package cn.tedu.web;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import cn.tedu.domain.User;
import cn.tedu.service.UserService;
@Controller
public class UserServlet {
@Autowired
UserService userService=null;
public void addUser(User user){
userService.addUser(user);
}
public void delUser(int id){
userService.delUser(id);
}
public User queryUser(int id){
return userService.queryUser(id);
}
}
有线程问题存在(多个线程、同一个共享资源、至少有一个在写,三者有一个都会造成线程问题)
加锁会降低效率所以使用本地线程变量解决此问题
package cn.tedu.demo;
//本地线程变量测试
public class Demo1 {
private static ThreadLocal<String> tl=new ThreadLocal<String>();
public static void main(String[] args){
tl.set("hello from main~");//向当前线程内部内部map中存储了键值对
A();
}
public static void A(){
B();
}
public static void B(){
C();
}
public static void C(){
D();
}
public static void D(){
System.out.println("d..."+tl.get());//从当前线程内部map中取值
tl.remove();
}
}
修改上述事务项目(SpringDay04_03aop_demo项目)
package cn.tedu.util;
import java.sql.Connection;
//事务管理提交回滚(改进)
public class TransactionManager {
//private static Connection conn=JDBCUtils.getConn();
private static ThreadLocal<Connection> tl=new ThreadLocal<Connection>(){
protected Connection initialValue(){
return JDBCUtils.getConn();
};
};
private TransactionManager(){
}
public static void startTran(){
try {
tl.get().setAutoCommit(false);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static void commitTran(){
try {
tl.get().commit();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static void rollbacktTran(){
try {
tl.get().rollback();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static Connection getConn(){
return tl.get();
}
public static void release(){
JDBCUtils.close(tl.get(), null, null);
tl.remove();
}
}
4.通过aop进行权限管理
通过aop来进行权限管理,通过自定义注解声明业务方法是否需要进行权限控制,通过注解上属性声明需要什么样的权限
代码实现:
package cn.tedu.anno;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import cn.tedu.enumration.PrivEnum;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PrivAnno {
PrivEnum[] value();
}
package cn.tedu.aspect;
import java.lang.reflect.Method;
import java.util.Arrays;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import cn.tedu.anno.PrivAnno;
import cn.tedu.enumration.PrivEnum;
import cn.tedu.test.Test01;
@Component
@Aspect
public class PrivAspect {
@Around("execution(* cn.tedu.service..*.*(..))")
public Object around(ProceedingJoinPoint pjp) throws Throwable{
Object obj=pjp.getTarget();
MethodSignature signature=(MethodSignature) pjp.getSignature();
Method method=signature.getMethod();//接口上的方法
Method instMethod=obj.getClass().getMethod(method.getName(), method.getParameterTypes());
if(instMethod.isAnnotationPresent(PrivAnno.class)){
PrivAnno pano=instMethod.getAnnotation(PrivAnno.class);
PrivEnum[] privs=pano.value();
//.判断是否有权限
if(Arrays.asList(privs).contains(Test01.tl.get())){
return pjp.proceed();
}else{
throw new RuntimeException("权限不够");
}
}else{
return pjp.proceed();
}
}
}
package cn.tedu.enumration;
public enum PrivEnum {
ADMIN,SUPERADMIN,USER;
}
package cn.tedu.service;
import org.springframework.stereotype.Service;
import cn.tedu.anno.PrivAnno;
import cn.tedu.enumration.PrivEnum;
@Service
public class UserServiceImpl implements UserService{
@PrivAnno({PrivEnum.ADMIN,PrivEnum.SUPERADMIN})
@Override
public void add(){
System.out.println("增加用户...");
}
@PrivAnno({PrivEnum.SUPERADMIN})
@Override
public void del() {
System.out.println("删除用户...");
}
@Override
public void queryUser() {
System.out.println("查询用户...");
}
}
package cn.tedu.web;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import cn.tedu.service.UserService;
@Controller
public class UserServlet {
@Autowired
UserService userService=null;
public void addUser(){
userService.add();
}
public void delUser(){
userService.del();
}
public void queryUser() {
userService.queryUser();
}
}
package cn.tedu.test;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.tedu.enumration.PrivEnum;
import cn.tedu.web.UserServlet;
public class Test01 {
public static ThreadLocal<PrivEnum> tl=new ThreadLocal<PrivEnum>();
@Test
public void test00(){
new Thread(new Runnable() {
@Override
public void run() {
tl.set(PrivEnum.SUPERADMIN);
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
UserServlet userServlet=(UserServlet) context.getBean("userServlet");
userServlet.addUser();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
tl.set(PrivEnum.ADMIN);
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
UserServlet userServlet=(UserServlet) context.getBean("userServlet");
userServlet.delUser();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
tl.set(PrivEnum.USER);
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
UserServlet userServlet=(UserServlet) context.getBean("userServlet");
userServlet.addUser();
}
}).start();
}
//public static PrivEnum role=PrivEnum.ADMIN;
@Test
public void test01(){
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
UserServlet userServlet=(UserServlet) context.getBean("userServlet");
userServlet.addUser();
}
@Test
public void test02(){
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
UserServlet userServlet=(UserServlet) context.getBean("userServlet");
userServlet.delUser();
}
@Test
public void test03(){
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
UserServlet userServlet=(UserServlet) context.getBean("userServlet");
userServlet.queryUser();
}
}